XPages provides a number of options for holding global variables at various hierarchical levels. Scoped variables allow data items to be scoped to application, session (browser session), view and request. But the values cannot be calculated dynamically within the map itself. However, they can easily be updated by accessing the map from SSJS or Java and just replacing the value. DataContexts are very powerful for holding global variables scoped to a smaller area than an XPage. They also allow you to streamline and avoid redundancy in complex code. The values can be computed on page load or dynamically and referenced via Expression Language via the var property (i.e. “#{varName}”).

But there are times when you want the smaller scope that a dataContext offers, you want to avoid redundant code and the resulting performance hits of putting it in multiple places for a rendered property, but you don’t want the value to be recomputed every time you refresh the page. But you do need the value to change based on certain interaction from the user. But there are no simple helper methods for accessing and updating a dataContext.

The use case I had recently was showing entries in a dataView where I wanted to restrict to a category based on clicking a link. So I wanted the user to toggle between showing a single hard-coded category and showing all. The current toggle value was needed to define the label of a section and the text of the link to toggle. The eventHandler of the link also needed to set a sessionScope variable for the category to display. So I didn’t want to code it on all three of those properties (plus potentially others in the future). In the past I would have used a viewScope variable, and that is still a valid option. But then I need to handle setting that viewScope variable as well as the sessionScope variable on page load and need myself and future developers to ensure the viewScope variable is unique. I wanted to type less, make it easier to support, more self-contained and avoid any potential variable name conflicts. The dataContext variable name was showAll and the (default) value was computed on page load to retrieve or set the sessionScope variable and sets its own value accordingly. Because it’s computed on page load, it’s great for performance.

<xp:dataContext var="showAll">
<xp:this.value><![CDATA[${javascript:try {
if (sessionScope.get("catFilter")==null) {
sessionScope.put("catFilter",userBean.commonName);
}
(@Contains(sessionScope.get("catFilter"),userBean.commonName)) ? false : true;
} catch(e) {
openLogBean.addError(e, this);
return false;
}}]]></xp:this.value>
</xp:dataContext>

The section header value was computed to "#{javascript:(showAll) ? "All Documents" : "My Documents";}", easy to understand and support.

The link text was computed to Switch to #{javascript:(showAll) ? "My Documents" : "All Documents";, again easy to understand and minimising SSJS for performance. (Unfortunately the version of Expression Language in XPages doesn’t allow the type of simple if statements SSJS does.)

There was just one place to change it, the eventHandler of the link to toggle the value. All it needed to do was access the dataContext, set the value to the opposite of its current value and update the sessionScope variable. The code to toggle the dataContext was just two lines of code:

importPackage(uk.co.intec.base);
return Utils.toggleDataContext(view,"showAll");

All the magic is then done in Utils.toggleDataContext(parentComponent, varName). And because I’m lazy and likely to use the code many more times, I’ve put it on XSnippets. I won’t reproduce the code here, but just some brief explanation.

toggleDataContext retrieves the dataContext from its parent component, gets the boolean value, and sets it to its opposite.

getDataContext retrieves all dataContexts that are children of the parent component, loops through them and returns the dataContext matching the variable name passed in.

getDataContextList gets all the dataContexts that are children of the parent component as a List of DataContext objects. The complexity here is that the parent component could be a UIViewRoot2 (XPage or Custom Control) or a UIPanelEx (Panel). So it needs to check.

So after the import in SSJS I need just one line of code to toggle the dataContext – quick to type, easy to test and less prone to errors. I can also use uk.co.intec.Utils.getDataContext(parentComponent, varName).setValue("myNewValue") directly, to access and change the value of a non-boolean dataContext. Again, quick and easy, with less typing.

1 thought on “Programmatically Accessing and Updating DataContexts”

  1. I realize this post is pretty old but I’m only now (!) exploring data contexts. In the case of a custom control, what is the pro/con of using a data context variable vs a composite data variable? In my case, the value would be computed on page load ($()) and would be invariant.

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Scroll to Top