Blog

XPages Bindings: When # Runs at Page Load

  |   Blog   |   12 Comments

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.

AUTHOR - Paul Withers

Paul Withers has been an IBM Champion since 2011, has been an OpenNTF Board Member since 2013, has worked with XPages since 2009, co-authored XPages Extension Library and was technical editor for Mastering XPages 2nd Edition. He is one of the developers on OpenNTF Domino API as well as contributor to a variety of other OpenNTF projects.

12 Comments
  • Tim Tripcony | Feb 9, 2012 at 4:00 pm

    Excellent explanation.

  • Sven Hasselbach | Feb 9, 2012 at 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 | Feb 9, 2012 at 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 | Feb 10, 2012 at 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 | Feb 10, 2012 at 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 | Feb 10, 2012 at 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 | Feb 10, 2012 at 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 | Feb 10, 2012 at 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 | Feb 10, 2012 at 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 | Feb 10, 2012 at 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 | Feb 12, 2012 at 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 | Feb 13, 2012 at 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.

Post A Comment