Archive | February 2013

My First NotesIn9 Episode

My first NotesIn9 episode has been posted: Jailbreak Your XPages View Columns

In the episode, I talk about several ways to enhance the output of columns in a view panel, which, by default, just displays text from an underlying view column. Fortunately, there are several options to customize it:

  • Computing a column value with SSJS
  • Passing HTML through a view column
  • Passing JavaScript through a view column
  • Mixing SSJS, HTML, and client-side JavaScript to retrieve back-end data and generate client-side output
  • Hijacking a view column to take complete control of its output

There are demonstrations of hijacking a view column output by displaying an iFrame within a view column as well as rendering a dojo chart within each row, reading data from the underlying documents and using it to generate the chart with client-side dojo code.

The chart uses a custom control, so there is also discussion about using custom control properties as well as using the “#{javascript: }” syntax to evaluate server-side statements into client-side javascript code.

Please take a look and let me know what you think.

And if you’ve ever considered contributing to NotesIn9 — go for it! David Leedy is a pleasure to work with and he provided all the information that I needed to make this happen as easily as possible.

Advertisements

Computed When Composed Fields in XPages

One of the first conceptual lessons we learn in XPages is that a Computed Field control does not provide the functionality of all variations of a Computed Field in the Notes client — it’s really analogous to a Computed for display field. However, we can still approximate the rest of the Computed Field functionality with a little bit of understanding of how it needs to work.

Mapping Notes Client Field Types to XPages

Along with specifying a field’s data type in the Notes client, you have 4 options for the field type: Editable, Computed, Computed for display, Computed when composed.

Here’s how they map to XPages core controls:

Notes Client XPage
Editable Edit Box
Computed Computed Field (and set the value via code as the document is processed)
Computed for display Computed Field
Computed when composed ???

To approximate a Computed field, we just need to have a Computed Field control bound to a document field and add code that sets the field value when the document is saved (or at any other point while processing the page).

Computed When Composed Field Requirements

Computed when composed fields are a bit trickier. They need to meet the following criteria:

  1. The value must be set before the page is rendered
  2. The value must be available for other fields to reference as the page is rendered
  3. The value must only be set when the page is first created (and not re-computed)

We know that it will need to use a Computed Field control, but the trick is how and when to set the initial value so that it truly is computed when the form is composed. For example, if you have a form that displays certain fields based on a ‘Type’ value, that value will need to be set before a new document loads, so the hide formulas can compute based on it.

A Couple of (Less than Ideal) Options

One option is to create hidden editable fields and set their default values and then create corresponding Computed Field controls to display them. This way, the values are computed one time, but still not editable on the front end.

Another option might be to set the Computed when composed field on the underlying form and use the compute with form option. Aside from the fact that you probably just died a little on the inside at that suggestion, it’s just not good design to have to maintain logic on the underlying Notes client form if you don’t have to.

A Better Option

The best method that I’ve found has these two steps:

  1. Add a Computed Field control and bind it to the underlying form field
  2. Use code on the beforePageLoad event to set the value on the document if it is new

Here’s a simple snippet of code that you can run on the beforePageLoad event:

if (document.isNewNote()) {
  document.replaceItemValue(fieldName, newValue);
}

This sets the value of the field on the document and allows other fields to be rendered or computed based on it.

Timing is (almost) Everything

It is important to note that the timing is very important in this working properly. The beforePageLoad event allows the values to be set early enough in the JSF life cycle that they are available before the page is generated and rendered to the browser. It does not work on the beforeRenderResponse event. I believe this is because the JSF component tree has already been built and components already have their values by this time, so it’s too late in the life cycle to allow other fields to be rendered based upon it.

For more information, see Peter Presnell’s informative post on the order of events firing when an XPage is loaded.

Paul Withers has also written a great explanation of the JSF life cycle.

Be careful to use the XSP Document

I have most recently used this technique successfully with the replaceItemValue() method of the XSP document, as shown in the code snippet above.

document.replaceItemValue()

I’ve had other code that set values on back-end documents by getting a handle to the underlying document.

document.getDocument().replaceItemValue()

The latter did not work well with the implementation of computed when composed fields for two reasons:

  1. The values showed up on the form and appeared to work fine, but they were not actually saved to the back-end document, so I had to write code when saving to store them again. When the XSP document is saved, the values on the XSP document overwrite what’s on the underlying document.
  2. Even though the values displayed on the page, they weren’t available to the page processing logic, so they didn’t work when rendered formulas were evaluated.

Alternate Solutions?

This being XPages, there are always many ways to solve the same problem.

What other ways have you dealt with Computed when composed fields?

Time picker with 24-hour/military time format (or any other custom time format) in XPages

It’s not straightforward, but with a little digging in the source, you can create a time picker with 24-hour time (aka military time) format in XPages. It sounds like a simple request, but it was slightly more complicated than you might expect. (Note: The same concept applies to any time picker with a Custom format.)

The properties for a time picker field generally look something like this:

MilitaryTimePicker_A

This produces this time picker in the UI:

MilitaryTimePicker_B

Changing the Time Format

To change the time format, I first checked the Time style drop-down, but none of its formats were 24-hour:

MilitaryTimePicker_C

I know that the custom format for 24-hour time is HH:mm, so I changed the Display format from “Time only” to “Custom” and selected HH:mm as the format (I manually removed the ‘z’ that was part of the format in the list).

MilitaryTimePicker_D

But the picker changed to a calendar picker on the front end!

MilitaryTimePicker_E

Time Picker Source

Here’s the source code generated when it’s set to Time only:

<xp:inputText id="scheduledTime"
  value="#{doc.scheduledTime}>
  <xp:this.converter>
    <xp:convertDateTime type="time">
    </xp:convertDateTime>
  </xp:this.converter>
  <xp:dateTimeHelper></xp:dateTimeHelper>
</xp:inputText>  

Here’s what it changed to when I set it to Custom and set the format:

<xp:inputText id="scheduledTime"
  value="#{doc.scheduledTime}>
  <xp:this.converter>
    <xp:convertDateTime pattern="HH:mm">
    </xp:this.converter>
  <xp:dateTimeHelper></xp:dateTimeHelper>
</xp:inputText>

The Solution

Changing the Display format to Custom added the pattern attribute, but removed the type="time" attribute from the xp:convertDateTime tag, which changed it back to the default date picker.

So, with the Display format set to Custom and the pattern set to HH:mm, I just added the type="time" attribute on line 4 to force it to be a time picker.

<xp:inputText id="scheduledTime"
  value="#{doc.scheduledTime>
  <xp:this.converter>
    <xp:convertDateTime type="time" pattern="HH:mm">
    </xp:convertDateTime>
  </xp:this.converter>
  <xp:dateTimeHelper></xp:dateTimeHelper>
</xp:inputText>  

Now, it is a time picker in 24-hour format:

MilitaryTimePicker_F

XPages Tip: Edit an XPage that won’t open normally in Domino Designer

If playing around with the source of an XPage or Custom Control messes it up so badly that you can’t even edit it anymore, here’s a trick to be able to fix it.

See, I have this, um, friend — yeah, that’s it — and <cough>he</cough> really messed up an XPage by moving things around in the source to try to shove event handlers in places they weren’t meant to be. He told me that it messed up his custom controls so badly that they wouldn’t even open. A tab for the XSP Editor would start to display in DDE, but the control wouldn’t even open — the system would hang until it crashed.

Who (else?) would do something like that?

Fortunately, he told me that he found a way to fix it.

If you mess something up so badly that the XSP Editor can’t even render it without crashing, try opening it with a different editor.

Open the database in the Package Explorer view, locate the element and right-click on it, then select Open With > (XML Editor or Text Editor)

OtherXSPEditors

My friend was able to use this to remove the offending tags and restore the controls to a point where they could be edited in DDE.

Thank you for listening. My friend feels better now.

Blogging Rite of Passage

I haven’t even been blogging very long, but I already came to a point where I needed to search my own blog for a piece of code.

I used to give Chris Toohey a hard time about this frequently when he would search the web for a solution and end up finding it on his own blog, but I’m starting to understand. 🙂

I also noticed that Paul Withers alluded to the same thing in a comment in this post on Mark Roden’s blog

How often has this happened to you?

Fix Dojo-Enabled Field Sizes Part 2: Type-Ahead Fields

Type-Ahead fields are activated by dojo after the page loads and the post-processing causes them ignore some theme, custom CSS, and inline settings. This can cause inconsistency in your form UI. This post demonstrates how to fix the field height and width for type ahead fields, so they better match the rest of your form.

My previous post showed how to fix these settings on date picker fields.

As I mentioned in the previous post, even field width settings in the properties panel are ignored.

This screen shot shows a form with a type-ahead field, then 3 regular fields, then a date picker. You can see that the field sizes are different for the type-ahead field and the date picker.

DojoFieldSizes_1

Reviewing the Generated Source

We can fix them with dojo code after the form loads (and the dojo-enabled activation happens), but we need to understand what is generated.

This is the source of the type-ahead field that’s passed to the browser (note that it even includes the inline ‘size’ attribute that I set while trying to size the field):

<span id="view:_id1:_id6"></span>
<input class="xspInputFieldEditBox" id="view:_id1:location1" type="text" name="view:_id1:location1" size="50" />

But this is what the source ends up being after dojo processes the field to activate the type-ahead field:

<span id="view:_id1:_id6" dojotype="ibm.xsp.widget.layout.data.TypeAheadReadStore" jsid="view__id1__id6" mode="partial"></span>
<div aria-labelledby="view:_id1:location1_label" widgetid="view:_id1:location1" role="combobox" class="dijit dijitReset dijitInlineTable dijitLeft xspInputFieldEditBox dijitTextBox" id="widget_view:_id1:location1" 
dojoattachevent="onmouseenter:_onMouse,onmouseleave:_onMouse,onmousedown:_onMouse" dojoattachpoint="comboNode" wairole="combobox" tabindex="-1">
<div style="overflow:hidden;">
<div role="presentation" class="dijitReset dijitRight dijitButtonNode dijitArrowButton dijitDownArrowButton" 
dojoattachpoint="downArrowNode" wairole="presentation" dojoattachevent="onmousedown:_onArrowMouseDown,onmouseup:_onMouse,onmouseenter:_onMouse,onmouseleave:_onMouse">
<div class="dijitArrowButtonInner"> </div><div class="dijitArrowButtonChar">▼</div></div>
<div class="dijitReset dijitValidationIcon"><br></div>
<div class="dijitReset dijitValidationIconText">Χ</div>
<div class="dijitReset dijitInputField"><input aria-invalid="false" value="" tabindex="0" id="view:_id1:location1" aria-autocomplete="list" aria-haspopup="true" role="textbox" name="view:_id1:location1" autocomplete="off" class="dijitReset" dojoattachevent="onkeypress:_onKeyPress,compositionend" dojoattachpoint="textbox,focusNode" wairole="textbox" waistate="haspopup-true,autocomplete-list" type="text"></div></div></div>

Fixing the field size

The logic for this one is a bit more complicated than the date picker, because there isn’t a unique class that’s applied to the field. The unique object to locate is the span tag with the dojotype attribute of ibm.xsp.widget.layout.data.TypeAheadReadStore (line 01). We then need to set the size on the subsequent div (line 02) and the field will size itself to fill the div.

We can get a handle to that div with the CSS ‘adjacent sibling’ selector: +

dojo.query('SPAN[dojotype="ibm.xsp.widget.layout.data.TypeAheadReadStore"] + DIV').style({
  height:"17px",
  width:"200px"
});

Note: This logic assumes that you want all of your type-ahead fields to be the same size. If you need to set some at different sizes, you can add unique classes to fields and target them separately with a few additional lines of code.

Fix Dojo-Enabled Field Sizes Part 1: Date Pickers

Dojo-enabled fields ignore some theme, custom CSS, and inline style settings. This can cause inconsistency in your form UI. This post demonstrates how to fix the field height and width for date picker fields, so they better match the rest of your form.

I refer to anything processed by dojo after the page loads as a ‘dojo-enabled’ field. Two common types that I encounter are date pickers and type-ahead fields. Their functionality is added by dojo once the form loads, so some settings that you may expect are not preserved.

Take a look at these screen shots (the same form with and without data). I took my simple Team form in my database of NFL football teams and set the Location field to be type-ahead and the Next Game field to be a date picker. Without changing anything else or adding any CSS, you can see that the dojo-enabled fields are longer horizontally and shorter vertically. Their fonts differ as well.

DojoFieldSizes_1b DojoFieldSizes_1

Field Width via the Properties Panel

If I set the field width in the properties panel, it is not respected in the dojo-enabled fields.

DojoFieldSizes_2

Field Styles with CSS

If I use CSS to set the font color and width of all fields, I still see the same effect. The color setting is picked up, but the field widths of the dojo-enabled fields are still different. Font sizes are also not respected by the dojo-enabled fields.

Reviewing the Generated Source

This is the source of the date picker that’s passed to the browser (note that it even includes the inline ‘size’ attribute):

<input class="xspInputFieldDateTimePicker" id="view:_id1:inputText1" type="text" name="view:_id1:inputText1" size="50" />

But this is what the source ends up being after dojo processes the field to activate the date picker:

<span class="xspInputFieldDateTimePicker" style="display: inline-block;">
</span>
<div class="dijit dijitReset dijitInlineTable dijitLeft xspInputFieldDateTimePicker dijitTextBox" id="widget_view:_id1:inputText1" role="presentation">
<div style="overflow: hidden;">
<div class="dijitReset dijitValidationIcon"></div>
<div class="dijitReset dijitValidationIconText">Χ</div>
<div class="dijitReset dijitInputField"><input class="dijitReset" id="view:_id1:inputText1" tabindex="0" type="text" autocomplete="off" value="" /><input style="display: none;" type="text" name="view:_id1:inputText1" /></div>
</div>
</div>
<span class="xspInputFieldDateTimePicker" id="view:_id1:inputText1_Container" style="display: inline-block;">
<span class="dijit dijitReset dijitLeft dijitInline xspInputFieldDateTimePicker dijitButton">
<span class="dijitReset dijitRight dijitInline"><span class="dijitReset dijitInline dijitButtonNode">
<button class="dijitReset dijitStretch dijitButtonContents" id="dijit_form_Button_0" style="-moz-user-select: none; background: none repeat scroll 0% 0% transparent; margin: 0px;" tabindex="0" title="" role="button" type="button" value="">
<span class="dijitReset dijitInline xspInputFieldDatePickerIcon">
<span class="dijitReset dijitToggleButtonIconChar">✓</span>
</span>
<span class="dijitReset dijitInline dijitButtonText dijitDisplayNone" id="dijit_form_Button_0_label"></span>
</button></span></span></span></span>

Fixing the field size

Since the date picker gets a class of xspInputFieldDateTimePicker, we can use few lines dojo code to fix the problem that dojo causes. Just run code like this on the onclientload event of the XPage or custom control to fix the font size and field width as needed.

dojo.query(".xspInputFieldDateTimePicker .dijitTextBox").style({
  width:"100px",
  height:"17px"
});

Note: This logic assumes that you want all of your date pickers to be the same size. I think this is a fairly safe assumption, since your date fields should all have a consistant format. However, if you need to set some at different sizes, you can add classes to the date fields and target them separately with a few additional lines of code.

Some inline styles still take precedence

I found it noteworthy that if I set the font style inline (via the properties panel or directly in the source), the setting was preserved. This isn’t ideal design, but it is an option if you’re stuck.

Up Next

In the next post, I’ll show how to fix the field size on type-ahead fields.