Archive | Custom Controls RSS for this section

XPages Tip: Passing an Array to a Custom Control Property

Custom properties are extremely useful for modular design and reuse by sending custom values into each instance. There are a number of data types that can be selected, but no obvious way to pass an array value. In this post, I’ll describe the issue and how to work around it.

Custom Property Data Types

The default data type for a custom property is string.

There are a number of primitive data types available in the dropdown:

Custom Property - Primitive Types

If you click the folder icons, there are a number of additional options, including Converters, Validators, and other types, but there are no data types for arrays (or vectors or JavaScript objects).

Custom Property - Property Types

String Data Type

In this case, I want a property that can accept an array of values.

To test this, I created a simple custom control with two properties, stringProperty and objectProperty, to test how they handle arrays. They both default to string as the data type.

Custom Property - 1 Custom Property

<xc:ccTest>
  <xc:this.stringProperty><![CDATA[#{javascript:return ['1', '2', '3', '4', '5'];}]]></xc:this.stringProperty>
  <xc:this.objectProperty><![CDATA[#{javascript:return ['1', '2', '3', '4', '5'];}]]></xc:this.objectProperty>
</xc:ccTest>

You can leave the data type as string, but compute an array to return. It won’t throw an error, but it will treat it like a single string.

No Data Type

You can remove the data type from the property definition and it won’t throw an error on the custom control. However, that is not a valid property, so its treated as though that property doesn’t exist.

If you’ve already set up an instance of the custom control and passed a value to it, it will throw an error on the custom control instance: Unknown property this.. It is not defined on tag .

Custom Property - Error - No Property Type Defined

Custom Data Type

Fortunately, there’s a really simple solution — you can manually type in a property type.

If you type in object as the type, it does the trick. (It effectively works as desired, although it actually accepts the data as java.util.Vector.)

Custom Property - Object Type

Advertisements

XPages Tip: Reading Custom Properties and Modifying a Component Before a Page Loads

If you need to read a property on a custom control and do something to any component on the page before a page loads, it can get tricky because the compositeData object is not available in the beforeRenderResponse event and getComponent() does not work in the beforePageLoad event.

I have an application where I need to dynamically inject components before a page loads. However, the injection depends on custom properties on a custom control, so it needs to read the properties and then get a handle to a component and modify it. Since the compositeData object isn’t available in the beforeRenderResponse event and getComponent() doesn’t work in the beforePageLoad event, there’s no single place to put the code that I need.

Fortunately, there’s a simple workaround. Code in the beforePageLoad event can read custom properties from the compositeData object and store them in viewScope variables. Then, code in the beforeRenderResponse event can read those values from viewScope and use getComponent() to get the handle to the component that I need to modify.

MWLUG Slides – AD114 Take Your XPages Development to the Next Level

In this session at MWLUG 2015, Paul Calhoun and I dug into a number of features already available in XPages, but not as widely used.

We only had time to cover half of the sections, but the full set of slides is available here

Topics include:

  1. Application Responsiveness (primarily JSON RPC)
  2. SSJS Tips
  3. Modifying Component output
  4. Java Tips
  5. Custom Controls (including dynamic field binding to make reusable fields)
  6. Resources for learning more
  7. Debugging Tips
  8. Event handlers
  9. Dojo

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?

XPages Tip: Accessing a custom control’s custom property from outside of the custom control

If you’ve used custom properties, then you’re aware that the compositeData object provides access to those properties within the custom control. However, you can also access those properties from outside of the custom control. In this post, I’ll show how.

Accessing a Custom Property from Within a Custom Control

Let’s start with a custom control named myCC that has a custom property named myProperty. Here’s what it looks like to include it on an XPage and pass in a value of myValue:

<xc:myCC myProperty="myValue"></xc:myCC>

On the custom control, you can refer to that value as compositeData.myProperty. Here’s an example of a computed field that displays the property value.

<xp:text escape="true" id="computedField1" 
  value="#{javascript:return compositeData.myProperty;}">
</xp:text>

Accessing a Custom Property from Outside of a Custom Control

If you have a need to access the a value passed to a custom property of a custom control from outside if the custom control, there are two steps to take:

  1. Add an id to the custom control instance on the page (so you can refer to it)
  2. Get the custom control component, retrieve a map of its property values, and then access the property that you need

Here’s an updated example of the custom control implementation on the XPage, with an id attribute added.

<xc:myCC myProperty="myValue" id="ccID"></xc:myCC>

Here’s how to refer to the custom property from the XPage:

getComponent('ccID').getPropertyMap().getProperty('myProperty');

This concept will work fine with multiple instances of the same custom control within a page because each instance would be required to have its own unique ID.

If you want to make the property available in client-side Javascript, you can use the "#{javascript: }" syntax:

var propertyValue = "#{javascript:getComponent('ccID').getPropertyMap().getProperty('myProperty')";

A Use Case

Here’s an example where I’ve recently found this useful. I have an application where I have a flexible grid custom control that takes a parameter with the URL for a REST service to supply the data. When I execute a search, I don’t want to reload the entire page — I just want to call the REST service to get the updated results and apply them to the grid.

But the search field exists as part of the application layout, so it’s outside of the grid custom control. Since the grid control is used for several types of grids, the REST service will vary, so I need to read a custom property of the custom control from another place on the page. This allows the Search feature to be reusable like the custom control.

Reading a Custom Control Property Into Client-Side JavaScript

There are times when it’s helpful to get information from server-side JavaScript into client-side JavaScript. I find this most frequently when I have a custom control that uses a client-side library function, but needs information from a back-end document to work with. (For example, generating a chart with a client-side script library and plotting information from documents on the chart.)

“#{javascript: }” Syntax

If you have a custom control that accepts custom properties and needs to include them in client-side JavaScript, one method you have available to you is this syntax:

"#{javascript: SSJS_CODE_HERE}"

The server will evaluate the code between the colon (:) and closing curly brace (}) on the server side and replace the entire value between (and including) the quotes with the value that results from the server-side JavaScript statement.

Custom Properties

To get a custom property from a custom control, you can use the compositeData object. It automatically provides a handle to all custom properties passed to the custom control.

To get a custom property named myProperty in SSJS, you would use this statement:

var x = compositeData.myProperty;

So, to read the value of a custom control property into a client-side JavaScript statement, you just combine these two things:

var x = "#{javascript:compositeData.myProperty}";

Make sure it’s within an xp: tag

Even though the end result is client-side JavaScript, it requires server-side processing before the page is rendered, so this will *only* work within xp: tags. It will work within an xp:scriptBlock tag, but it will not work with pass-through JavaScript, such as a tag.

<xp:scriptBlock id="block1">
  var x = "#{javascript:compositeData.myProperty}";
</xp:scriptBlock>

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.