XPages Bindings: When # Runs at Page Load

As developers get more comfortable with XPages, one of the steps is to start to using the Compute on Page Load option instead of the Compute Dynamically option for Server-Side JavaScript. But there are times when that can’t be done. I encountered this last week and it took a chat with Jeremy Hodge for me to understand my problem. One of my colleagues had the same problem yesterday. And Sven Hasselbach has blogged about the same issue today. Unfortunately, it’s not a bug. It’s a fact of life and one also found in JSF.

 

Sven encountered the issue, as did I, in an Output Script control. Basically, if your Output Script code combine ${…} code and #{…} code, for example #{id:myField1}, the #{…} code is always evaluated at page load. This means, in the case of #{id:myField1} that it returns a blank ID. This isn’t limited to Output Script controls. It’s the same for any control, even a Computed Field.

 

One of the nice things about XPages, once you’ve mastered the basics, is the Custom language. This allows you to combine textual and computed elements in a single Value Binding, as I blogged about last July. But even in a Computed Field, you can’t combine ${…} and #{…}. Let’s put this in context.

 

Look at this code. It’s fairly basic. We’re outputting a username and control IDs.

Binding Code

But look at the output. For the first control, we get the ID. For the second, we get the username, but not the ID.

Binding Output

That’s because the ID for computedField1 has been generated at runtime, but the binding for computedField2 has been generated at page load. Basically, because we have something that needs generating at page load, everything needs running at page load.

 

This may seem strange. But if we understand what’s happening behind the scenes, it’s understandable. Any non-literal string is stored as a String and passed to a Java function. So whereas a developer might consider “${javascript:@UserName()}” as a distinct element, the XSP Command Manager just interprets the whole value property as something that needs passing to a Java method. Let’s look at the Java code outputted, and the difference becomes apparent.

 

The first control has the following Java code:

Java for computedField1

The whole value property, including the #{id:…} element is stored into a String , which is passed as a parameter to evaluator.createValueBinding() – not all parameters passed to the method are shown.

 

But compare computedField2′s Java code.

Java for computedField2

Here, again, the whole value property including the @UserName element is passed into a String. But notice it is passed in as #{…}. The ${…} serves only to tell Designer that it needs to call evaluator.getBindingValue() instead of evaluator.createValueBinding(). Because the value property is passed as a String parameter of a method, everything must use createValueBinding() or everything must use getBindingValue(). You cannot combine both, nor do I expect that you ever will.

 

Someone more knowledgeable in the intricacies of JSF can probably explain this  better than me. But the key to remember is to use #{…} or ${…}, but not both.


12 Comments for this entry

Tim Tripcony
February 9th, 2012 on 4:00 pm

Excellent explanation.

Sven Hasselbach
February 9th, 2012 on 4:15 pm

Thanks for your explanation, but I still think that this is not JSF compliant behaviour. If you add some apostrophes to the example above, you will see that the situation is a little more complicated:

The javascript won’t be executed anymore, but runs at page load!? If you look in the java classes, you will see, that the code is transformed like you are describing above. But this is not correct in my opinion.

If you enter something like this, you XPage won’t get saved, the Designer tells you that there is a bad syntax:

But not if you enter this one:

Looks very strange to me…

Just my two cents
Sven

    Sven Hasselbach
    February 9th, 2012 on 6:38 pm

    Damn! The tags are not displayed.

    Here is the code w/o tags:

    1.
    … value=”you are logged in as ‘${javascript:@UserName()}’. The field id is ‘#{id:computedField1}” …

    2.
    … value=”you are logged in as ‘#{}’. The field id is ‘#{id:computedField1}” ..

    3.
    … value=”you are logged in as ‘${}’. The field id is ‘#{id:computedField1}” ..

paulwithers
February 10th, 2012 on 11:53 am

Thanks Sven. I remembered as I came into work this morning that I hit similar challenges when I was writing the Extension Library book with the queryExpr property of the Dojo Combo Box and Dojo Filtering Select. One of the options for these properties is “*${0}”. Because ${ has a specific meaning, I needed to change it to “*$\{0}”, so escape the {. Then everything worked fine.

Jeremy Hodge
February 10th, 2012 on 12:16 pm

@sven this is actually JSF compliant. The spec actually says that you can not mix the two types in a single expression.

    Sven Hasselbach
    February 10th, 2012 on 12:38 pm

    @Jeremy:
    You are right, it is JSF compliant. I thought that there is a non-JSF-compliant behaviour. But it is just a bug in the designer.

Mark Roden
February 10th, 2012 on 6:28 pm

Paul – does this help for a work around?

This field’s value is ${javascript:@Text(“#{id:computedField2}”)}

You are logged in as ${javascript:@UserName()}.
This field’s value is ${javascript:@Text(“#{id:computedField2}”)}

    Mark Roden
    February 10th, 2012 on 6:31 pm

    Arrrrg it removed all the markup – let me know if that makes sense or not and I will post all the source somewhere else

Sven Hasselbach
February 10th, 2012 on 10:13 pm

@Marc:
What you are doing is no longer JSF compilant.

If you do something like this…
${javascript:@Text(“#{javascript:java.lang.System.currentTimeMillis()}”)}

…and refresh the element with a partial refresh, the value is recalculated for every time. This is not what should happen if you are calculating a value on page load.

Mark Roden
February 10th, 2012 on 11:57 pm

Well I did wonder “why” it worked based on the explanation above I don’t think it should – but it does – at least 8.5.3

I put the whole code here so you can see it – http://xomino.com/2012/02/10/xpages-using-and-at-the-same-time/

So are we to assume that it might not work in the future?

Thanks

Sven Hasselbach
February 12th, 2012 on 7:28 pm

@Mark:
The “mystic” behaviour is caused by the internal handling of an expression. Please have a look at the class ‘com.ibm.xsp.util.ValueBindingUtil’. It seems to be used to identify the type of an expression. I have made some tests and think that the classes have been coded extremly – ehm – quick. F.e. by adding a blank at the end of the expression string the provided methods are returning wrong results…

If someone at the IBM corrects this code, the code you provided would not work anymore (because it then would be JSF compliant).

    Mark Roden
    February 13th, 2012 on 7:33 pm

    @Sven – you are right. I have added a note to my original blog post stating as such – thanks :)

    I found a bug in Notes, there’s a first.

3 Trackbacks / Pingbacks for this entry

XPages – using # and $ at the same time « Xomino, February 10th, 2012 on 9:07 pm

[...] Paul Withers posted a great about the XPage Binding and how the order of computing for $(..) and #(..) means that the following code does not compute as we would want it to. The article is well explained and opened my eyes to the intricacies of the timing in JSF. It got me thinking about it and I think I have a solution. [...]

“Compute Dynamically” Vs. “Compute on Page Load” | blog@hasselba.ch, February 11th, 2012 on 7:17 pm

[...] Dynamically” und “Compute on Page Load” zu befassen, denn der hervorragende Artikel von Paul Withers erläutert zwar die grundsätzlichen Unterschiede zwischen den beiden Berechnungsvarianten, [...]