Archive | October 2013

Dojo Data Grid – Part 29: Displaying the Row Count

In this post, I’ll show how display a row count for the grid and update it after executing a search.

Dojo Data Grid Series

Dojo Grids in XPages — All Blog Posts

All About the Timing

The grid has a rowCount property which will generally return the number of rows in the grid.

It will work fine if you check it by clicking a button after the page loads. However, if you run this immediately as the page loads (even if it’s in the onClientLoad event), it will return 0, because the grid hasn’t been drawn out yet).

At this point, my solution is to introduce a delay to give it time — then it can return the correct amount.

Displaying the Count

One simple way to display the count is to put a simple span tag on the page, add a class to it so it can be programmatically updated.

I added this to my page:

Row Count: <span class="displayRowCount"></span>

Updating the Count

Another consideration is that you don’t just want to check the count when the page loads, you’ll want it to be updated any time the grid is refreshed.

In the post where I showed how to add search to a grid I mentioned that executing a search must refresh the rest service and the grid, so you should put them both in a panel and target that panel with a partial refresh.

To finish this solution, add code that will check the grid’s row count and update the display (span) tag on the onClientLoad event of the panel, so it re-runs every time the panel is refreshed.

var t=setTimeout(function(){
    var myGrid = dijit.byId('#{id:djxDataGrid1}');
    dojo.query('.displayRowCount')[0].innerHTML = myGrid.rowCount;
  }
,500);

This code waits half of a second (500 milliseconds) and then checks the grid’s row count (line 2) and updates the span tag to display it (line 3).

These screen shots show the row count below the grid after initial load and then after a search:
Grid 29 - 1

Grid 29 - 2

REST Service Note

I tested this with a JSON rest service as the source for the grid. Interestingly, the service’s count property is set to 20, so it shouldn’t be retrieving the full set of rows, but it returns the full count of over 1,300 anyway.

Advertisements

CSS Tip: Selecting an Element that has Two Classes

If you’re familiar with CSS, you know that you define the style for an element with a specific class by referencing .className{ } in a style sheet and you’re familiar with the hierarchy of selectors, but did you know that there’s a selector that looks for an element with two classes?

Here’s an example page with three div tags. The first one has class1, the second one has class2 and the third one has both class1 and class2.

<div class="class1">This is div 1</div>
<div class="class2">This is div 2</div>
<div class="class1 class2">This is div 3</div>

Here’s a simple style sheet that, when included on the page, will set the font color of class1 and class2:

.class1 {
color:#FF0000;
}

.class2 {
color:#00FF00;
}

Here is the result:
TwoClasses_1

The first div gets the red font because it has class1 assigned. The second div gets the green font because it has class2 assigned. The third div also gets the green font because class2 is the last class assigned to it, so it picks up the style from that class (when it conflicts with any style set by the first class).

Now, let’s say I want to make the third div’s font blue (without changing the style of the first two). I can’t change the class1 or class2 styles because that will change one of the other divs.

Fortunately, there’s a CSS selector that allows you to specify a style that applies to an element that has two classes. Just specify them as .class1.class2 with no space between the two class names.

This css entry will do the trick in the sample shown above:

.class1.class2 {
color:#0000FF;
}

This uniquely identifies the third div because it has both of those classes.

TwoClasses_2

Of course, this is an overly simplistic example, but I’ve had a few cases recently where this was helpful when working with objects that have multiple class names assigned by XPages and dojo.

The difference between two methods of adding client-side JavaScript event-handling code to an XPages input control

There are two ways to add event handling client-side JavaScript code to an XPages input control. This post shows the difference in what is generated and a use case for when the less-obvious method can be useful.

The Scenario

I recently worked on an application designed for a touch screen interface where there are a lot of data entry fields.

In order to make it easier to use, I want it to automatically select the contents of a field when the field receives focus. This way, the user can easily change the value of a field without having to click into a field, select the contents, then delete the existing value and re-enter a new value.

If the contents can be automatically selected when the user sets the focus on a field, then the user can just start typing and it will replace the value.

It may not sound like much, but this is a significant improvement in usability on a touch screen, without using a mouse.

The JavaScript

This is a simple problem to solve on a standard web page. You can put this code on the onfocus event of a field to automatically select the contents:

this.select();

JavaScript Keyword: this

In JavaScript, the keyword this can be used to refer to the object receiving the event that has triggered the handler code.

This is very handy for getting the value of the current field or taking some other action on the field with a very compact syntax. In my case, I was trying to get a handle on the current field in order to select its contents.

Adding JavaScript via the Events View

The standard way to add client-side JavaScript event code is through the Events view. I went there and added the code to the client-side onfocus event.

JSEventCode_1

Here’s what the XPage source looks like:

<xp:inputText id="inputText1" value="#{document1.Field1}" defaultValue="--">
  <xp:eventHandler event="onfocus" submit="false">
    <xp:this.script><![CDATA[this.select();]]></xp:this.script>
  </xp:eventHandler>
</xp:inputText>

This is the HTML and JavaScript generated when the page is rendered:

...
<input type="text" value="--" id="view:_id1:inputText1" name="view:_id1:inputText1" class="xspInputFieldEditBox">
...
<script type="text/javascript">

function view__id1__id4_clientSide_onfocus(thisEvent) {
alert('Value: ' + this.value);
this.select();
}

XSP.addOnLoad(function() {
XSP.attachEvent("view:_id1:_id4", "view:_id1:inputText1", "onfocus", view__id1__id4_clientSide_onfocus, false, 2);
}); 

</script>

This is how client-side JavaScript is added on the XPage. It creates a function and runs code on page load to attach it to the event. In this case ‘this’ is not attached directly to the field.

When I click on the field (thus setting the focus and triggering the onfocus event), I see an error in firebug.

JSEventCode_1b_FirebugError

Workaround

There are ways to work around this limitation. If you add a unique class to the field or compute the client-side ID with pass-through EL syntax (“#{id:inputText1}”), you can get a handle to the field. But this is a little more effort that shouldn’t be necessary.

Adding JavaScript via the Properties View.

I noticed that there’s another place to add onfocus event code. If you click on the field and open the Properties view rather than the events view, you can go to All Properties > events > onfocus. Click on the icon in that field and you can enter JavaScript code.

JSEventCode_2

Code added this way is clearly managed differently than the standard event code. I noticed that code entered via All Properties doesn’t show up in the Events view and vice versa.

There’s a big difference in the output as well. Rather than the JavaScript function and code to attach it to the event handler, code entered this way is passed directly through to the generated input tag.

<input type="text" value="--" id="view:_id1:inputText2" name="view:_id1:inputText2" class="xspInputFieldEditBox" onfocus="this.select();">

This is exactly what I wanted to begin with!

And it works as expected.

Caveat

Since code entered this way is passed directly through, you cannot set it to execute a partial refresh (or trigger any other server side update directly). However, if you need a quick snippet of code that only needs to work with the client-side DOM, this is an option.

You can, however, still include pass-thru EL statements. You just have to realize that, since it’s putting the code directly into the client-side onfocus event, it will already be surrounded by double-quotes by default, so use single quotes instead and account for that.

Update: Handling this.select() in Chrome

It turns out that this.select() doesn’t work in Chrome. It briefly selects the text but immediately loses the selection.

There are two easy workarounds. (1) You can use the onclick event instead. (Tabbing into the field with the keyboard will automatically select the text anyway, so keyboard access is also covered.) (2) You can add return false; to the onmouseup event to allow it to work as well.

This sample field works in Chrome to select the contents when you click on the field:

<xp:inputText id="inputText1" defaultValue="myDefault"
  onfocus="this.select();" onmouseup="return false;">
</xp:inputText>

More on Using Dynamic Value Binding to Create a Reusable Field

In my last post, I showed how to use dynamic value binding to create a custom control to reuse a field. In this post, I’ll describe another use case, dig into the functionality a little further, and show one way to enhance it.

Another Use Case

Another use case for this functionality — the case where I first used this functionality — is a scheduling application.

I have a schedule form set up to display the schedule for a single day, but it has to work for any day of the given week.

Rather than create 7 sets of fields to bind them to the appropriate document fields or leave all fields unbound and write code to read values and write them the correct fields, this design pattern allows me to dynamically bind the fields and pass in an index for the specific day being displayed.

In addition, there’s jQuery code activating a type ahead feature, code that runs on a field event, validation, etc. All of this would be more tedious and complicated to manage if repeated over and over again dozens times on the same form.

Using Dynamic Field Binding

As I showed in the previous post, here’s an example of a combobox that’s on a reusable custom control and set up for dynamic value binding:

<xp:comboBox id="comboBox1"	
  value="#{compositeData.dataSource[compositeData.MyFieldName]}">
  <xp:selectItem itemLabel="Strongly Agree"></xp:selectItem>
  <xp:selectItem itemLabel="Mildly Agree"></xp:selectItem>
  <xp:selectItem itemLabel="Neutral"></xp:selectItem>
  <xp:selectItem itemLabel="Mildly Disagree"></xp:selectItem>
  <xp:selectItem itemLabel="Strongly Disagree"></xp:selectItem>
</xp:comboBox>

This code works as is to bind to the data source and field name passed into the custom control when it’s added to the XPage.

It is important to understand, though, that there is a limit to how dynamic the field binding can be; it cannot execute a computation within the value binding.

Let me explain.

In my scheduling application, I have a set of fields that is reused for any day of the week. Say that the field name on the underlying document is Date_1 for Sunday, Date_2 for Monday, and so on, and I’m storing the current day of the week in a sessionScope variable called DayNumber.

It does not work if the field binding is set up like this:

value="#{compositeData.dataSource[compositeData.MyFieldName + sessionScope.DayNumber]}"

However, that doesn’t mean it’s not possible — it can be done with the original version of the value binding shown in the first code snippet. The solution is to execute the computation before passing the field name into the custom control.

<xc:ccDynamicallyBoundField
  dataSource="#{javascript:return document1;}"
  Rating_FieldName="#{javascript:return 'Date_' + sessionScope.scheduleDay;}">
</xc:ccDynamicallyBoundField>

Accessing the Value of a Dynamically-Bound Field from the Data Source

As an enhancement, I wanted to have a computed text control that displays the value in read mode, because comboboxes don’t display nicely in read mode.

While trying to use this with two different data sources (one a document and the other a JSON object), I noticed that it’s a little more complicated to compute within SSJS because it’s not as powerful as EL in its resolution.

I can bind the data source with this format dataSource[FieldName], but, although that syntax works with a JSON object, SSJS cannot use that same syntax to retrieve a field from a document.

In order to work with both types of data sources, I had to enhance the computed text control to check the data source type and treat it differently if it’s a document.

This syntax does the job:

if (typeof compositeData.dataSource == 'NotesXspDocument') {
  // Data Source is Notes Document
  return compositeData.dataSource.getItemValueString(compositeData.MyFieldName);
} else {
  // Data Source is JSON
  return compositeData.dataSource[compositeData.MyFieldName];
}

Using Dynamic Value Binding to Create a Reusable Field

In XPages, you can compute the value binding of an input control. In this post, I’ll show how to use the powerful capability in order to streamline your design by creating custom control that allows you to reuse a field as needed for consistency, flexibility, and ease of maintenance.

A Simple Use Case

A simple use case for this functionality would be a survey application where forms could consist of many questions with similar sets of options for a response. Rather than creating the same combobox or radio button group over and over, you could have a single field designed as needed and reused for all questions that require the same options.

This would be especially useful if you develop dynamic form-building capability that allows users to specify any number of questions and build the form on the fly.

Advantages of this Design Pattern

There are several advantages to modularizing the design in this way, rather than creating several instances of a field with the same design over and over.

  • Easy to reuse
  • Easy to maintain list values, styling, etc
  • Easy to maintain more complex functionality (event handling code, validation/error handling)
  • Ability to bind the field to a document data source or some other data source

Creating the Reusable Field Custom Control

1) Create a custom control and add custom properties

Create a property for the field name / object property name. This will define where the data will be stored. This property is a string.

Create a property for the data source. This step isn’t required if you just want to assume the data source name (e.g. if all fields will be stored on document1), but it allows you to make the custom control much more flexible.

Set the property type to be a data source. Click the folder icon next to the Type field, expand Data Sources, and select dataInterface.

DynamicValueBinding_2_DataSourceProperty

You can set the Editor to be a Data Source Picker, but it doesn’t quite work the way you’d expect, so it’s not necessary. (Explanation below.)

DynamicValueBinding_1_CustomProperty

2) Add the reusable field and set its value binding. In this case, I have a combobox with 5 standard rating values that will be reused throughout the page.

<xp:comboBox id="comboBox1"	
  value="#{compositeData.dataSource[compositeData.Rating_FieldName]}">
  <xp:selectItem itemLabel="Strongly Agree"></xp:selectItem>
  <xp:selectItem itemLabel="Mildly Agree"></xp:selectItem>
  <xp:selectItem itemLabel="Neutral"></xp:selectItem>
  <xp:selectItem itemLabel="Mildly Disagree"></xp:selectItem>
  <xp:selectItem itemLabel="Strongly Disagree"></xp:selectItem>
</xp:comboBox>

The Power of EL

The computed value binding for the field in line 2 above is what makes this flexible design pattern possible. It combines the flexibility of XPages (allowing dynamic value bindings) with the power of Expression Language in order to define a value binding that is flexible enough to work with multiple types of data sources.

The EL syntax of dataSource[propertyName] will evaluate for an object property as well as a document field name!

compositeData is the object that provides the handle to all property values passed into a custom control, so compositeData.dataSource evaluates to the data source that is passed in. compositeData.Rating_FieldName is the property for the name of the field to which the value will be bound.

Using the Custom Control

Here’s an example of the source of an XPage that will use 3 instances of the field. In each case, it passes in the same data source but a different field name.

Question 1:
<xc:ccDynamicallyBoundField 
  dataSource="#{javascript:return document1;}"
  Rating_FieldName="Field1">
</xc:ccDynamicallyBoundField>
<xp:br></xp:br>

Question 2:
<xc:ccDynamicallyBoundField
  dataSource="#{javascript:return document1;}"
  Rating_FieldName="Field2">
</xc:ccDynamicallyBoundField>
<xp:br></xp:br>

Question 3:
<xc:ccDynamicallyBoundField 
  dataSource="#{javascript:return document1;}"
  Rating_FieldName="Field3">
</xc:ccDynamicallyBoundField>

Passing the Data Source

I mentioned earlier that you can set up the data source custom property of the custom control to be a data source picker (screen shot above shows it), but that it doesn’t work as expected.

It appears to work in that it lets you choose from a list of data sources on the page, but it does not actually work to pass the data source! It essentially passes a string with the name of the data source. The property looks like this:

dataSource="document1"

Instead, you need to compute the property that’s being passed to the custom control to return the data source:

return document1;

This sets the property passed to the custom control as shown in the code snippet that uses the custom control earlier in this post.

I’ve tested this with a document data source as well as a JSON object data source.

Up Next

In the next post, I’ll describe another use case and show how to extend this functionality a bit.

Dojo Data Grid – Part 28: Overriding Grid CSS

In the last post, I showed how to modify the look and feel of a Dojo Data Grid in XPages by selecting a different dojo theme. In this post, I’ll show how to further customize the UI by adding your own CSS.

Dojo Data Grid Series

Dojo Grids in XPages — All Blog Posts

Default Style

Here’s what the grid looks like by default:

Grid 28 - A

Grid Classes to Target

In order to figure out how to override the styling, we need to understand more about the structure of the grid on the page.

There are a lot of divs and tables that get generated when a grid is rendered. There’s a parent grid div, header and view divs, scrollbox and content divs, and then each grid row is a div and table.

Here’s a list of elements that it uses from the start of the grid down to the first data cell:


div.dojoxGrid > div.dojoxGridMasterView > div.dojoxGridView > div.dojoxGridScrollbox > div.dojoxGridContent > div[role="presentation"] > div.dojoxGridRow > table.dojoxGridRowTable > tbody > tr > td.dojoxGridCell

Every other div.dojoxGridRow also gets the dojoxGridRowOdd class as well.

Font and Row Color

Fortunately, we don’t need to go through all of that to find the classes that we need to customize.

You can change the row color and font by targeting .dojoxGridRow tr

/* Grid Row - Default Styles */
.dojoxGridRow tr {
  background-color: #2F4F4F;
  color: #FFFFFF;
  font-size: 14px;
}

Fixing Header/Cell Alignment with Column Widths

Once you start changing default fonts (or padding), it throws off the alignment of the column headers to the column data.

Grid 28 - B

The simplest way to fix this is to define the width of each grid column explicitly in the grid column properties. This ensures that the header and cell line up.

Grid 28 - C

Alternate Row Color

You can also change the alternate row color and font by targeting .dojoxGridRowOdd tr

/* Grid Row -- Alternate Row Background Color*/
.dojoxGridRowOdd tr {
  background-color: #778899;
}

Row Hover

It’s a little trickier, but you can also override the row hover styles. In this case, I’m changing the background color, text color, and font size.

/* Grid Row - Hover Styles */
.dojoxGridRow tr:hover td {
  background-color: white !important;
  color: #2F4F4F !important;
  font-size: 18px;
}

Grid 28 - D

Header

You can also modify the style of the column header cells. You have to target both the header cell and the div contained within the header cell in order to fully change the background color, which uses an image by default.

/* Grid Header - Styles */
.dojoxGridHeader .dojoxGridCell {
  background-image: none !important;
  background-color: #777777 !important;
}

.dojoxGridHeader .dojoxGridCell div {
  color: white;
  font-size: 12px;
}

Dojo Data Grid – Part 27: Changing the Dojo Theme

If you’d like to change the look of a dojo grid, you can do so by changing the dojo theme. As in XPages, dojo themes are a set of resources (images and style sheets) that define the UI. In this post, I’ll show the 4 built-in dojo style themes and how you can use them with your grid.

Dojo Data Grid Series

Dojo Grids in XPages — All Blog Posts

Dojo Themes

There are 4 dojo themes available:

  • tundra
  • claro
  • nihilo
  • soria

With a standard (non-XPages) web page, you would include the main style sheet for the theme and then set the class of the body tag for that theme in order to use it.

For example:

<link rel="stylesheet" href="dojo/dijit/themes/claro/claro.css" />
...
<body class="claro">

Dojo Themes in XPages

When using the dojo data grid control in XPages, it loads the tundra theme by default, as shown by these tags in the page source:

<link rel="stylesheet" type="text/css" href="/xsp/.ibmxspres/dojoroot-1.6.1/dijit/themes/tundra/tundra.css">
...
<link rel="stylesheet" type="text/css" href="/xsp/.ibmxspres/dojoroot-1.6.1/dojox/grid/resources/Grid.css">
<link rel="stylesheet" type="text/css" href="/xsp/.ibmxspres/dojoroot-1.6.1/dojox/grid/resources/tundraGrid.css">
...
<body class="xspView tundra">

Using the Claro theme

The tundra theme is used by default, but you can change the grid to use the claro theme with these two steps:

1) Add the claro grid style sheet to the page

<xp:this.resources>
  <xp:styleSheet href="/.ibmxspres/dojoroot/dojox/grid/resources/claroGrid.css"></xp:styleSheet>
</xp:this.resources>

2) Add a dojo attribute to the grid called class and its value to claro

Note:I’m not sure why, but this doesn’t work with nihilo and soria, even though similarly-named style sheets exist in the same location.

Changing the Dojo Theme

If you want to change the grid to use the soria or nihilo themes, you change the dojo theme application-wide via an XPages theme. As with a standard web page, we need to include the correct style sheet and add the class to the body tag of the page.

Credit to this solution goes to the XPages Extension Library book. I’m assuming this chapter was written by Paul Withers, since I also found it in this Lotusphere presentation.

<!— Include Dojo stylesheet —>
<resource dojoTheme="true">
  <content-type>text/css</content-type>
  <href>/.ibmxspres/dojoroot/dijit/themes/soria/soria.css</href>
</resource>

<!— Add style to body element —>
<control dojoTheme="true">
  <name>ViewRoot</name>
  <property mode="concat">
    <name>styleClass</name>
    <value>soria</value>
  </property>
</control>

The ViewRoot attribute makes this possible and the property mode ‘concat’ will append the class name to the page’s body tag.

Since we’re using a theme, this will be an application-wide setting, so it will affect the look of other dijit controls on your pages, but they will all be consistent with the same theme.

Interestingly, when I change the dojo theme for the application, then the individual class attributes for all 4 dojo themes all seem (provided you’ve included the grid-specific stylesheets on the page)!

Here’s how each style sheet is included — only include the one you’d like to use:

<xp:this.resources>
  <xp:styleSheet href="/.ibmxspres/dojoroot/dojox/grid/resources/claroGrid.css"></xp:styleSheet>
  <xp:styleSheet href="/.ibmxspres/dojoroot/dojox/grid/resources/soriaGrid.css"></xp:styleSheet>
  <xp:styleSheet href="/.ibmxspres/dojoroot/dojox/grid/resources/nihiloGrid.css"></xp:styleSheet>
</xp:this.resources>

Here’s an example of 5 copies of the same grid. The first does not have a dojo class attribute. The others have specified a class attribute that corresponds to a dojo theme. The page shown includes the 3 style sheet resources shown above and also has an XPages theme in place that changes the default dojo theme. (Note: In this case, the soria theme is loaded as the application default, so the default grid is the same as soria.) Click the image to enlarge it.

Grids - With App Theme to Change Dojo Theme

For what it’s worth, this is what the same page looks like when there is not an XPages theme in place overriding the dojo theme.

Grids - No App Theme

Dojo Themes and Enhanced Grids

It’s easier to change the dojo theme when using an EnhancedGrid, because you already have to specify the grid style sheets to load, so you can just load the ones that you’d like.

It appears that there are three options for enhanced grids:

  • default
  • claro
  • tundra
<xp:styleSheet href="/.ibmxspres/dojoroot/dojox/grid/resources/Grid.css"></xp:styleSheet>
<xp:styleSheet href="/.ibmxspres/dojoroot/dojox/grid/enhanced/resources/EnhancedGrid.css"></xp:styleSheet>

Enhanced - Default

<xp:styleSheet href="/.ibmxspres/dojoroot/dojox/grid/resources/claroGrid.css"></xp:styleSheet>
<xp:styleSheet href="/.ibmxspres/dojoroot/dojox/grid/enhanced/resources/claroEnhancedGrid.css"></xp:styleSheet>

Enhanced - Claro

		
<xp:styleSheet href="/.ibmxspres/dojoroot/dojox/grid/resources/tundraGrid.css"></xp:styleSheet>
<xp:styleSheet href="/.ibmxspres/dojoroot/dojox/grid/enhanced/resources/tundraEnhancedGrid.css"></xp:styleSheet>

Enhanced - Tundra

More Information

Take a look at the dojo theme documentation for more information.

To see more dojo controls in different themes, check out the Dijit Theme Tester page