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]; }
