Archive | July 2014

Displaying a dGrowl message from SSJS

In a recent NotesIn9 video, I showed how to use the dGrowl Dojo plugin to create growl-style messages in XPages. Jesse Gallagher and Frank Van der Linden showed how to trigger growl-style message from server-side code with Java. In this post, I’ll round out the discussion with an SSJS snippet to do the same.

view.postScript()

As in Jesse’s and Frank’s examples, the key method here is view.postScript(). This method adds a client-side snippet to run after a server-side refresh occurs. I believe it has been available since 8.5.3.

As Jesse mentioned, the biggest challenge here is usually escaping characters properly, remembering that you’re using server-side code to write out client-side code.

The concept is simple, though — take the client JS from an example message and, if it only uses single quotes, wrap it in double quotes and pass it through.

var notificationJS = "dg.addNotification('Here is an info message...',{'channel':'info', 'duration': 3000});";
view.postScript(notificationJS);

Full Refresh vs Partial Refresh

This works fine with both full and partial refreshes. However, if you use a partial refresh, you would have the ability to run the script multiple times and display separate messages (as needed), whereas a full refresh would clear all messages because it refreshes the entire page.

Adding New Message Styles to dGrowl

In NotesIn9 episode 147, I demonstrated how to implement the dGrowl Dojo plugin in XPages. The plugin comes with two message styles: info and error. In this post, I’ll show how to enhance it to add success and warning styles.

dGrowl_Enhanced

Take a look at the live demo page to see these in action.

In order to add a new message type, all you have to do is add a few lines of CSS to define the new message style and update the dGrowl object creation code to add the new channel.

Adding New Message Styling

This starts with the assumption that you have already implemented the dGrowl plugin in your application, as shown in the NotesIn9 video.

You’ll need to go through Package Explorer to locate the stylesheet, since it’s part of the plugin files installed under the WebContent folder.

dGrowlCSS

Open dGrowl.css and add rules for additional message styles.

Here’s an example that I set up by copying the .dGrowl-channel-error block styling. I changed the class name and updated the color scheme (based on the OneUI message styling).

/* 'Warning' Channel */
.dGrowl-channel-warning .dGrowl-notification {
  background-color: rgb(255, 255, 188);
  border: 1px solid rgb(246, 230, 146);
}

/* 'Confirmation' Channel */
.dGrowl-channel-confirmation .dGrowl-notification {
  background-color: rgb(236, 249, 223);
  border: 1px solid rgb(200, 226, 184);
}

Adding the New Message Channel

In the script block that instantiates the new dGrowl object, just add two additional channels and define the position number to order them.

<script type="text/javascript">
  var dg = new dGrowl({'channels':[
    {'name':'error', 'pos':1},
    {'name':'warning','pos':2},
    {'name':'confirmation','pos':3},
    {'name':'info','pos':4}
  ]});
</script>

The key is that the channel name must match the end of the class name in the CSS. (For example: .dGrowl-channel-confirmation styling will be used by the channel named confirmation) If the names don’t match, then your message will get the default (info) message styling.

Now the channels are set up and ready for messages.

dg.addNotification('Warning Message',{'channel':'warning', 'sticky':true});
dg.addNotification('Confirmation Message',{'channel':'confirmation', 'sticky':true});

NotesIn9 Episode 147 – dGrowl in XPages

NotesIn9 episode 147 demonstrates how to implement the dGrowl plugin to add growl-style messages to an XPages application. This provides a nice UI for a different style of message to display to the user and it allows you to set an automatic timeout or display the message until the user closes it. More importantly, the demo shows how to incorporate a Dojo plugin into an XPages application.

I set up a page in my demo application to test it out.

The plugin comes with two message styles: info and error. In my next blog post, I’ll show how to enhance it to add success and warning styles.

Changing the Search Behavior of a Dojo Filtering Select in XPages

The default behavior of a Dojo Filtering Select control is to take what you type and filter the options in the list based on what options start with that value. In this post, I’ll show how to change it to search any part of the value (more like a Select2).

Default Filtering Behavior

To demonstrate, I set up this Dojo Filtering Select:

FilteringSelect_SearchMiddle_1

(This post shows the easiest way to create a Dojo Filtering Select)

<xe:djFilteringSelect id="djFilteringSelect2">	
  <xp:selectItem itemLabel="abc"></xp:selectItem>
  <xp:selectItem itemLabel="bcd"></xp:selectItem>
  <xp:selectItem itemLabel="cde"></xp:selectItem>
  <xp:selectItem itemLabel="efg"></xp:selectItem>
  <xp:selectItem itemLabel="fgh"></xp:selectItem>
  <xp:selectItem itemLabel="ghi"></xp:selectItem>
  <xp:selectItem itemLabel="hij"></xp:selectItem>
</xe:djFilteringSelect>

As I type a letter, it filters the list down to any values that start with that letter:

FilteringSelect_SearchMiddle_2

Searching Any Part of the Value

If you want to change the behavior to match any part of the value when searching, you can update the queryExpr property. Dojo documentation says that you need to set it to "*${0}*" for the desired outcome.

${0} will return the value that the user has typed into the field so far. The default behavior is "${0}*", but if you also add the wildcard (*) before the search term, it will look for the term anywhere in the value.

Updating queryExpr in XPages

The Dojo Filtering Select control has a queryExpr property. However, entering this search term does not bring the desired result.

If you enter *${0}* into the property (XPages will automatically enclose all attribute values in double quotes), it looks good in the source of the page…

<xe:djFilteringSelect id="djFilteringSelect2" queryExpr="*${0}*">

… but it breaks the field (you get a default value, but no drop-down list) because it ends up sending this to the browser:

<select dojoType="dijit.form.FilteringSelect" queryExpr="*0*" id="view:_id1:djFilteringSelect2" name="view:_id1:djFilteringSelect2">

It is automatically removing the $, {, and } characters.

Fortunately, we can fix this pretty easily by computing the value and escaping each of those characters with a backslash (\).

return '*\$\{0\}*';

Now our source tag in XPages looks like this:

<xe:djFilteringSelect id="djFilteringSelect2"
  queryExpr="#{javascript:return '*\$\{0\}*';}">

This allows it to pass the value through to HTML properly, which fixes the field and enables the behavior that we’re looking for.

If I type a ‘c’ into the field, I know see a list filtered to all options that have a ‘c’ anywhere in the value!

FilteringSelect_SearchMiddle_3

Updating the Highlighting Behavior

When you change the default search behavior, the highlighting of the value in the field seems odd. I type a ‘c’ into the field, and it auto completed the field with the first value that contained a ‘c’, but highlighted everything after the first character (since I type in 1 character).

This now seems counterintuitive since it’s not only filtering from the front of the list.

Using the autoComplete property of the Dojo Filtering Select, we can stop this behavior.

If you set autoComplete to false, then it won’t automatically fill in the first matching value.

FilteringSelect_SearchMiddle_4

I like this a lot more from a usability perspective. Just be aware that, since it’s not autocompleting with a valid value, if you leave the field before selecting a value, you’ll get an error because the field does not contain a valid value. (Although that validation can also be turned off.)

Here is the full source of my field, including these updates:

<xe:djFilteringSelect id="djFilteringSelect2"
  queryExpr="#{javascript:return '*\$\{0\}*';}" autoComplete="false">

  <xp:selectItem itemLabel="abc"></xp:selectItem>
  <xp:selectItem itemLabel="bcd"></xp:selectItem>
  <xp:selectItem itemLabel="cde"></xp:selectItem>
  <xp:selectItem itemLabel="efg"></xp:selectItem>
  <xp:selectItem itemLabel="fgh"></xp:selectItem>
  <xp:selectItem itemLabel="ghi"></xp:selectItem>
  <xp:selectItem itemLabel="hij"></xp:selectItem>
</xe:djFilteringSelect>

Mask Converters in XPages

If you want to force the data entered by a user into a certain pattern (for structured values such as dates and phone numbers) you can use mask converters. In this post, I’ll show how to implement them and explain what they do (and don’t do).

Adding a Mask Converter

To add a mask converter to a field, select the Data subtab of the field properties and change the Display type value to Mask.

Once you do this, a field will display below for you to enter the mask pattern.

MaskConverter - 1 - Field Property

Primary Input Markers

Mask patterns can contain input markers and literal characters.

The 3 most common input markers are the following:

  • ? – a letter
  • # – a digit
  • A – a letter or digit

You can use these to define a pattern of a specific number of letters and/or digits.

For example, to define a value with 3 letters (such as a country code), the pattern would be ???.

Pretty straightforward.

Input Converter != Input Mask

At this point, it’s important to understand that the result of this might be different than you’d expect.

1) There is no visual indicator that a field is masked.
2) The data entry is not restricted in any way.
3) If you save the form and the data in any field doesn’t match the mask, then it appears that nothing happens.

If you have an Display Error control next to a masked field or a Display Errors control at the top of the page, you’ll see that it throws a “Source string is unmatched with mask pattern.” error in this case. (If you manually enter data that matches the defined mask pattern, the form is saved successfully.)

Even though you may have expected an input mask on the field, the behavior makes sense conceptually because it’s a converter; converters work to format the data after you enter it and submit the form (and before it’s displayed when viewed later).

You’ll need to display the pattern somewhere near the field or you will drive your users crazy by not letting them know how the data needs to be entered.

Input Mask jQuery Plugin

If you’re looking for an input mask, check out this post by Marky Roden regarding a jQuery plugin.

Including Literal Characters

Now back to the mask converter…

Defining the quantity of letters and digits is useful, but it’s often even more helpful to include literal characters to help format the data to increase the readability.

For example, a US phone number is more readable when in this format: (###) ###-####

As I sat to write this post, I did a cursory search and found that Brian Moore has also written about this recently. Take a look at his approach to removing literal characters in a phone number.

Other examples where literals are useful in formatting the data are credit card numbers, social security numbers, and dates (although date pickers are generally much more convenient to work with).

You may also have other patterns that are custom to your organization, such an an invoice number that starts with ‘INV-‘. You could have a pattern like this: INV-#####

Computing a Mask Pattern

You can also compute the mask pattern, in case it needs to change based on some other factor. However, it is computed on page load, so do not expect it to change during a page refresh.

I could see a use case where you’d have some kind of identifier that starts with the current year. Here is a simple computed pattern to define this:

var d = new Date();
return d.getFullYear() + '-' + '#####';

The asis property

The asis property determines whether to filter out any literal characters in the mask.

The default is false, which will keep any formatting characters in the data saved to the field.

You can modify the property by selecting the input control, going to the All Properties subtab and then locating the mask under data>converter

Other Pattern Input Markers

There are a few other markers that you can use when defining the mask pattern:

  • H – a hex character (0-9, A-F)
  • * – anything
  • ‘ – escape a formatting character
  • U – convert lowercase to upper case
  • L – lowercase stay lowercase

Passing Parameters to SSJS from a Client-side partialRefreshGet()

partialRefreshGet() is a handy method of the client-side XSP object that can be used to trigger a partial refresh from client-side JavaScript. In this post, I’ll show how you can pass parameters for SSJS to read during the refresh, which allows you to send information to the server-side code without submitting a less efficient POST request.

This is an interesting tip that I picked up from the Mastering XPages book. I’ve used partialRefreshGet() numerous times, but I wasn’t familiar with the params property previously.

Here’s an example of a normal partialRefreshGet() call:

XSP.partialRefreshGet("#{id:myComputedText}", {});

The first parameter is the target for the partial refresh. This is client-side JavaScript, so it needs to use the #{id: } syntax to compute the client-side ID of the refresh target.

The second parameter is an object that have up to 4 properties: onStart, onError, onComplete, and params. Here’s an example of the structure when using all of the options (although none are required):

XSP.partialRefreshGet("#{id:myComputedText}",
 {
    params: paramObject,
    onStart: startHandler,
    onError: errorHandler,
    onComplete: completeHandler

 });

The params Property and the param Object

The params property takes an object with parameters to send with the AJAX call. The Mastering XPages book says that the params property “gets expanded, encoded, and appended to the GET request URI that is invoked by the underlying AJAX handler.”

This gives you an easy way to pass information from client-side JS to SSJS and then access it via the param object in SSJS, which provides access to all URL parameters.

The SSJS that’s intended to read the parameters passed by a partialRefreshGet much be within the specified refresh target in order to read the parameters during the refresh.

Simple Example

If I have a computedText component with this value:

if (param.containsKey('parameter1')) {
  return param.parameter1 + ' ' + param.parameter2;
}

It will not return anything when the page first loads.

If I add a button with this client-side JavaScript…

XSP.partialRefreshGet("#{id:computedField2}", 
  {
    params:{"parameter1":"1", "parameter2":"2"}
  });

… it will display 1(space)2 after I click the button, because it is the refresh target and it can read URL parameters sent during the refresh.

This is a very efficient way to send data to a server-side script.

Note: If you pass a parameter that already exists in the URL, it does not overwrite the URL parameter value — it turns the value into a string separated by a comma and a space between the values.

Interesting Quirk with Custom Property Names

I came across an interesting quirk when defining custom properties within a custom control — there are some names that cannot be used.

While working on a reusable control for charting functionality, I wanted to add a custom property called chartTheme. As I started to type the name, it let me type ‘cha’, then prevented the ‘r’ from working. I initially thought something was wrong with the key on my keyboard, because it let me type other characters. After fiddling with it for a moment, I realized that it just refused to allow the property to be named ‘char’.

To work around it, I typed the ‘t’ next and then added the ‘r’ afterwards. (After the word ‘chart’ was in the field, it would not let me delete the ‘t’, which would have changed the word back to ‘char’.)

I tried other data type names and found a similar issue. Then I tried other keywords (true, class, etc) and got the same result.

It looks like a limitation on reserved words in Java in general. (Logically, this makes sense because everything is compiled down to Java.)

I found tested these reserved words and tested them all and verified that they are cannot be used:

  • abstract
  • assert
  • boolean
  • break
  • byte
  • case
  • catch
  • char
  • class
  • const
  • continue
  • default
  • double
  • do
  • else
  • enum
  • extends
  • false
  • final
  • finally
  • float
  • for
  • goto
  • if
  • implements
  • import
  • instanceof
  • int
  • interface
  • long
  • native
  • new
  • null
  • package
  • private
  • protected
  • public
  • return
  • short
  • static
  • strictfp
  • super
  • switch
  • synchronized
  • this
  • throw
  • throws
  • transient
  • true
  • try
  • void
  • volatile
  • while

I also noticed that ‘con’ and ‘nul’ are not allowed.

This can be annoying when typing a property name, but it’s easily worked around by adding a different character and then fixing it.

I’m curious to hear if you’ve had similar experience.

1. Are there any other words that you’ve come across?

2. Are there other places where you’ve seen this limitation?