In this post, I showed how to set all labels in an application to include a class to pick up Bootstrap styling so it could be applied application-wide and not require touching every label control individually. However, there’s a quirk with label rendering that may make it not apply universally as desired. In this post, I’ll explain the issue and how to use another theme setting to easily fix it.
Updating all Labels via the Theme
This code in the theme will apply the
control-label class to all label components in the application. This allows me to apply a Bootstrap style class to all labels without having to update each label control individually on every XPage and custom control.
<control> <name>Text.Label</name> <property mode="concat"> <name>styleClass</name> <value>control-label</value> </property> </control>
The Bootstrap styling will be applied to
label tags that have the
The Problem with Label Rendering
However, there’s an issue with the way labels are rendered that may not make it work consistently.
Any labels that do not have a
for attribute specified will actually be rendered as
span tags and the styling will not be picked up. (Labels that have the
for attribute specified will be rendered as
label tags and work as expected.)
In another post, I described the effects of different modes on theme property application. In this post, we’ll see a practical example of the effects.
Theme to the Rescue (Again)
Fortunately, there’s an easy way to add another property setting to the theme to handle this.
There isn’t a
tagName attribute on a label, so you can’t directly modify the output tag this way, but
for is a property of the control, so you can use the theme to add it to all labels.
1. Overriding the Property
One option is to override the
for property on all labels. Lines 7-10 were added below to do so.
<control> <name>Text.Label</name> <property mode="concat"> <name>styleClass</name> <value>control-label</value> </property> <property mode="override"> <name>for</name> <value>dummyTarget</value> </property> </control>
This puts the
for property in place and assumes it needs to figure out the client-side ID of the element that’s been specified. This is a dummy value, but it does the job.
<label id="view:_id1:_id3:_id51:office_Label1" class="control-label" for="view:_id1:_id3:_id51:dummyTarget">Office</label>
However, it does the job too ambitiously. It removes any existing
for property, so it would break the association with the specified input control, which may cause other issues with the application and most certainly would cause issues with a screen reader.
2. Concatenating the Value
Changing line 7 to concatenate instead of overriding the value gives us a bit better behavior.
This mode will append the property value to any value that currently exists for the attribute. It will also add the attribute and value if it doesn’t exist.
<label id="view:_id1:_id3:_id51:label17" class="control-label" for="view:_id1:_id3:_id51:dummyTarget">Payment #</label>
This also does the job, but it causes two values to be in the for property if one already existed (although it doesn’t try to generate a client-side ID when it’s appended).
<label id="view:_id1:_id3:_id51:office_Label1" class="control-label" for="view:_id1:_id3:_id51:office1 dummyTarget">Office</label>
This is better than the override method, but still may cause problems.
3. Mode not specified
You can also just not specify the mode.
In this case it only adds the property and value if the property doesn’t already exist, so it’s the cleanest solution.
This is an example of a label that already had the
for attribute specified. It does not get the new dummy value.
<label id="view:_id1:_id3:_id51:office_Label1" class="control-label" for="view:_id1:_id3:_id51:office1">Office</label>
This is an example of a label that did not have the
for attribute specified:
<label id="view:_id1:_id3:_id51:requisitionLabel" class="control-label" for="view:_id1:_id3:_id51:dummyTarget">Requisition #</label>
Themes are commonly-used in XPages applications to include resources needed throughout an application, but they can also be a powerful tool for consistently applying application-wide control settings. In this post, I’ll explain the difference between different modes for applying a control property and link to a corresponding post with a practical example.
1. Overriding a Control Property
In this post, I showed how to use the theme to add a class to all labels in an application to pick up Bootstrap styling without having to set the class on each individual label.
Here’s an example of the theme code to make it happen:
<control> <name>Text.Label</name> <property mode="override"> <name>styleClass</name> <value>control-label</value> </property> </control>
When a page loads, the theme is applied to the page and all label controls are updated as the page is rendered.
- Line 2 is directing it to apply to all Label controls throughout the application. (This is using a theme ID that’s predefined for the label control, as noted in the Mastering XPages book.)
- Line 4 specifies that it’s updating the
styleClassproperty of the controls.
- Line 5 specifies the
control-labelclass to add to each label. (This is the class name that Bootstrap styling looks for.)
- Line 3 is the variable for this post. This example starts with the setting the override mode. This mode will set the class to the specified value on all label controls, overriding anything that may have been set when the control was added on an XPage or custom control.
2. Concatenating a Control Property
Instead of overriding the property on all controls, another option is to concatenate the specified value to any existing value specified on each instance of the control.
In this case, if there was a label control that already had a class specified, the
control-label class would be added to it (after a space) so the label would have both classes.
If the label control did not have a class, then the specified class would be added.
3. Conditionally Applying a Control Property
The last option is not to specify a mode at all.
In this case, it will not do anything to a label control that already has a class specified, but it will add the specified class to any label control that does not have one.