dominoGuru.com
Your Development & Design Resource
Customizing XPage RadioGroup Controls for Vertical Navigation Menus
09/07/2011 12:45 PM by Chris Toohey
While creating an XPages-based user interface for my Remote Console HD
application, I ran into a particular issue with the xp:radioGroup Control that
I think warrants sharing under the provision of "stuff that took me far longer
than it should of, therefore I'll save someone else the trouble once Google
indexes this post...".
The desired user interface for Remote Console HD meant that I would have to create a simple left-handed navigation menu ContentPane with the selected content displaying on the main/NotesView ContentPane.
Remote Console HD Demo Screencap - Click to Zoom
To get started, I used a dijit.layout.SplitContainer and two dijit.layout.ContentPane pass-thru HTML DIV Elements:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" dojoParseOnLoad="true"
dojoTheme="true" style="margin: 0px !important; padding: 0px
important">
<xp:this.resources>
<xp:dojoModule name="dijit.layout.ContentPane" />
<xp:dojoModule name="dijit.layout.SplitContainer" />
</xp:this.resources>
<div dojoType="dijit.layout.SplitContainer" orientation="horizontal"
sizerWidth="7" activeSizing="true" style="height: 100%; margin: 0px
!important; padding: 0px !important;">
<div
dojoType="dijit.layout.ContentPane" sizeMin="200" sizeShare="2"
style="margin: 0px !important;
padding: 0px !important; background-color: #eee;">
</div>
<div
dojoType="dijit.layout.ContentPane" sizeMin="400" sizeShare="10">
</div>
</div>
</xp:view>
This gave me my left-navigation, right-content layout. Now, all I needed to do was actually create my "navigation" controls.
I started with a radioGroup Control mostly so I can refer back to the Control value if needed:
<xp:radioGroup
id="selectedServers" layout="pageDirection"
style="border:
none;">
<xp:selectItems>
<xp:this.value>
<![CDATA[#{javascript:var slist =
@DbColumn("names.nsf","($Servers)",1);
@Text(@Name("[Abbreviate]", slist) + "|" +
slist)}]]>
</xp:this.value>
</xp:selectItems>
</xp:radioGroup>
Basing a simple Repeat Control on this radioGroup Control value, I was able to create the Server "cards" which are displayed on the right-hand side of the navigation (each with their own data source).It was simply a matter of writing my "card" and creating Panel Controls that themselves support their own data source for things like the Applications, Logs, or Remote Console-specific activity logs.
Wanting to make this resemble vertical tab navigation instead of a simple vertical-aligned series of radio-type INPUT Elements, I decided to hide the actual radio part of the Control with CSS and rely on the user click on the LABEL for each "server" they select.
First, you need to know what HTML a radioGroup Control generates:
<div id="view:_id1:frame_navigation" class="navigation">
<fieldset id="view:_id1:selectedServers" style="border: none;" class="xspRadioButton">
<table class="xspRadioButton" style="border: none;">
<tbody>
<tr>
<td>
<label>
<input type="radio" name="view:_id1:selectedServers" value="CN=acme/O=GBSBLOGS"> acme/GBSBLOGS
</label>
</td>
</tr>
...
</tbody>
</table>
</fieldset>
</div>
... and now that I know what my generated HTML will look like for my radioGroup Control, I simply style as desired:
div.navigation fieldset, div.navigation fieldset
table, div.navigation
fieldset table tbody, div.navigation fieldset table tbody tr, div.navigation fieldset table
tbody tr td, div.navigation
fieldset table tbody,
div.navigation fieldset table tbody tr td {
display: block;
margin: 0px !important;
padding: 0px !important;
}
div.navigation fieldset table tbody tr td label {
display: block;
width: 100%;
border-bottom:
1px dashed #666;
background-color: #fff;
font-weight:
normal;
margin: 0px;
padding: 20px 0px 20px 0px;
text-align:
left;
cursor: pointer;
background-image: url(listArrow.png);
background-position: center right;
background-repeat: no-repeat;
color: #666;
}
div.navigation fieldset table tbody tr td label input
{
visibility:
hidden;
}
radioGroup Control vs. CSS Styled radioGroup Control Vertical Navigation Menus
The navigation was working great at a technical level... but not so much from a user experience standpoint: I couldn't tell which of my "cards" were active (outside of reading the title) as the radioGroup Control does not change the Label when selected.
Of course, it's not intended to change the label (the active state is shown by filling in the "radio"...) but I really needed some way of changing the label -- preferably the className (class attribute of the LABEL Element) -- to "active" or something.
... after entirely way too much time spent trying to figure out how to do this, I came up with the following CSJS (Client-Side JavaScript) function:
function
navigation_active(obj) {
for (i=0; i<obj.length; i++)
{
if (obj[i].checked == true) {
obj[i].parentNode.className = 'active';
} else {
obj[i].parentNode.className = '';
}
}
}
-- and updating my radioGroup Control markup in my XPage:
<xp:radioGroup
id="selectedServers" layout="pageDirection"
style="border:
none;">
<xp:selectItems>
<xp:this.value>
<![CDATA[#{javascript:var slist =
@DbColumn("names.nsf","($Servers)",1);
@Text(@Name("[Abbreviate]", slist) + "|" +
slist)}]]>
</xp:this.value>
</xp:selectItems>
<xp:eventHandler
event="onchange"
submit="true" refreshMode="partial"
refreshId="frame_notesview">
<xp:this.script>
<![CDATA[navigation_active(document.getElementsByName('#{id:selec
tedServers}'))]]>
</xp:this.script>
</xp:eventHandler>
</xp:radioGroup>
And that's pretty much it really. Now, the LABEL Element's className is switched to "active" via the CSJS when I change a value on the radioButton Control.
NOTE: This technique will not work with Internet Explorer. You'll have to employ a UserAgent switch and compute the event (change it from "onchange" to "onclick".
... and earlier in this article I said "I started with a radioGroup Control..." mostly because by the time I though to write this article... I changed my mind.
Since I'm using a Repeat Control to dynamically build my Server "card", there's no reason I can't display multiple "cards"!
<xp:checkBoxGroup id="selectedServers" layout="pageDirection"
style="border:
none;">
<xp:selectItems>
<xp:this.value>
<![CDATA[#{javascript:var slist =
@DbColumn("names.nsf","($Servers)",1);
@Text(@Name("[Abbreviate]", slist) + "|" +
slist)}]]>
</xp:this.value>
</xp:selectItems>
<xp:eventHandler
event="onchange"
submit="true" refreshMode="partial"
refreshId="frame_notesview">
<xp:this.script>
<![CDATA[navigation_active(document.getElementsByName('#{id:selec
tedServers}'))]]>
</xp:this.script>
</xp:eventHandler>
</xp:checkBoxGroup>
Using a checkBoxGroup gets the job done as well, but this time it's multi-value!
Remote Console HD Demo Screencap using checkBoxGroup - Click to Zoom