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.

Advertisements

5 responses to “Using Dynamic Value Binding to Create a Reusable Field”

  1. Oliver Busse says :

    Is it possible to bind the datasource’s events to custom SSJS code or Java bean code? The custom control does not display the datasource events but this is where I want to create my code. I want to place some code in e.g. the querySaveDocument event. Calculating another datasource within the control from the compositeData datasource results in a save conflict after every save from the “main” datasource. Very tricky…

    • Brad Balassaitis says :

      The data source on the XPage containing the custom control will still have its events to execute. I haven’t tried it, but I would think that should work as normal. It would just be better to work directly with the fields on the back-end document rather than trying to refer to the UI components if you’re trying to determine get a value that’s been entered.

      It seems to make sense that calling a save on the data source passed into the custom control would cause a conflict, because the parent XPage (or custom control) also has an instance of the data source.

      The key is what exactly you need to do from the code on the reusable field custom control. I tend to not use data source events, but rather write a function called saveDocument() where I execute any logic that I need and then call document1.save() at the end. This way, I’m controlling when the save is executed, but only if all other processing completes successfully.

      • notacodemonkey says :

        Hi

        Did you find a solution for the problem with the selection of the datasource. If i cant select a datasource the ds picker in the custom property doesnt make any sense. I have removed it because it confused
        people who wanted to use my cc.

      • Brad Balassaitis says :

        I have not come across a better way than to compute it (although I haven’t spent any time trying). I agree that it’s not intuitive. I try to explain that in the comment that goes along with the property to show how it needs to work.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: