Suppose you have an XPage with a repeat control on it to show a list of documents. In the repeat you generate an <xp:button> for every document. Based on the status of the document you decide to give the button a different color, so you make the styleClass property of the button computed:
<xp:repeat id="repeat1" rows="30" var="entry"> <xp:this.value><![CDATA[#{javascript: print("computing repeat value"); return ["style1", "style2"]; }]]></xp:this.value> <xp:button value="Label" id="button"> <xp:this.styleClass><![CDATA[#{javascript: print("computing styleClass:"); print( typeof entry); return entry }]]></xp:this.styleClass> </xp:button> </xp:repeat>
That’s (roughly) the code you’d have to write. And guess what: it all works. Everyone’s happy!
So you decide to enhance the looks of your application and include Bootstrap. Bootstrap requires the btn class on all buttons for styling. Being an expert XPage developer you create a theme for your application, add the Bootstrap CSS file and add a control definition to give all buttons that btn class:
<control> <name>Button.Command</name> <property mode="concat"> <name>styleClass</name> <value>btn</value> </property> </control>
You reload the page, thinking you’re done and guess what: errors!
That’s roughly what I’ve been looking at today and at some point thinking I lost my sanity.
The print() statements in the code above were added by me to show the order of execution. Without the <control> definition in the theme I saw this on the server console:
> computing repeat value > computing styleClass: > string > computing styleClass: > string
Exactly what I expected! But… after adding the <control> definition I saw this:
> computing styleClass: > undefined > computing styleClass: > undefined > computing repeat value
Notice the subtle, yet very important, difference in the order of computing: with the <control> definition the styleClass is computed before (!) the repeat value, making it impossible to let the button style depend on the repeat value. This behaviour is caused by the mode=”concat” part, that should combine the value of the styleClass with the one set in the theme.
The Bootstrap4XPages plugin has that same <control> definition in it, so if you’re using that you will likely run into this some day.
The solution I came up with for now is to add a new <control> definition to the theme, setting it to override any inherited settings and setting the mode to the default (‘override’). Set the themeId to the new <control> name and it all works again:
<control> <name>Button.NoConcat</name> <property> <name>styleClass</name> <value>btn</value> </property> </control>
and:
<xp:button value="Label" themeId="Button.NoConcat"></xp:button>
I have no idea why it behaves this way and would have never guessed that a <control> breaks anything but the UI in my app. If anyone can share some light on this: please do!