The Data View is an extremely powerful control and the standard view control I use now. That’s some statement considering that prior to the Extension Library I avoided the View Panel as much as possible in favour of Repeat Controls. The View Panel I found very limiting both from the point of view of data sources as well as layout.
But there are always things you want to change. And while many of them are made available to developers via the Properties view and have been explained either in the XPages Extension Library book or by Brad Balassaitis, there are still some things that are not immediately straightforward.
One of those is changing the icons for expanding and collapsing a category view. The normal twistie icon may be perfectly acceptable for many people, but after using the old traditional Notes forum for many years, I’d rather have something else. Brad covers custom expand / collapse icons for the Detail facet, but the category icons are a bit more challenging. The main reason is there is no CSS class allocated to the images – they are just static HTML – so you have to get a bit creative. And although you can add a class, it’s added to the h4 DOM node you see in the markup for the category column below.
For my application I was using Font Awesome icons, so the scenario might be slightly unusual because I needed to replace the <img> tags with <i> tags with a class allocated. (I’m also using the latest release of Font Awesome, so the classes I was assigning are different to those in Russ’s database.) But the steps involved would be the same.
There were two approaches that I could take. One was create a custom renderer to amend the HTML before it was output to the browser – a bit more complex than I wanted or could afford time for, on this occasion. The second was use (Client-Side) JavaScript to modify the HTML after it had been output to the browser. As ever when attempting something complex, the key is to break it down into the steps required:
- Run a JavaScript function after the page is initially loaded.
- Run the same JavaScript function after any partial refresh.
- In the JavaScript, access the relevant DOM nodes.
- Modify the HTML.
The first step was coding the JavaScript to access the DOM nodes and modify the HTML, because I know it’s feasible run JavaScript on page load and after partial refresh, although I didn’t have that code to hand. So it’s sensible to be able to get the complex stuff working on page load and bother about partial refreshes later.
Because Dojo is bundled with XPages, it made sense for me to use that to manipulate the DOM nodes. But if you prefer jQuery, there’s no reason not to use that. The first step was to code the Data View in such a way as to enable me to easily get a handle on all category columns. The easiest way to do that was to allocate a styleClass to any categoryColumn objects I wanted to modify. I called it “catColumn”. There is no CSS applied, it’s just a mechanism to enable me to easily identify any category columns.
The next step was to write the JavaScript function itself. I already knew that dojo.query allows you to get an array of all nodes that match certain criteria and loop through the matching nodes accordingly. But Jesse Gallagher pointed me towards dojo.behavior which is a better option for applying functionality to DOM nodes. It’s fairly similar to dojo.query, but instead of running the query itself, you add a behavior which defines a query string and apply that behavior. The behavior has a found function that runs on the matching DOM nodes. The code is below:
Behavior = {
// Convert xp:pagers to Bootstrap
".catColumn a img": {
found: function(img_node) {
var imgSrc = dojo.getNodeProp(img_node, "alt").toLowerCase();
if (imgSrc.indexOf("collapse") >= 0) {
dojo.place('<i class="fa fa-minus-square"></i> ', img_node, 'replace');
} else {
dojo.place('<i class="fa fa-plus-square"></i> ', img_node, 'replace');
}
}
}
}
dojo.ready(function() {
dojo.behavior.add(Behavior);
dojo.behavior.apply();
});
dojo.subscribe("partialrefresh-complete", null, function(method, form, refreshId) {
dojo.behavior.apply();
});
The Behavior code searches for the class “catColumn” (which gets applied to the h4 tag), then gets the img tag within the anchor tag within it. From the HTML shown in Firebug, you can see that’s what we need to do to get a handle on the image. I then use getNodeProp to get the alt tag – the aria-label attribute you see in the Firebug screenshot. I check if “collapse” is anywhere in the lower-cased value and, if so, use dojo.place to replace the img tag with the relevant Font Awesome code.
The dojo.ready function adds and applies the behavior after the Dojo code has been loaded. The final bit, dojo.subscribe, applies the same behavior after a partial refresh. This uses Tommy Valand’s excellent code for hijacking partial refreshes, also available in Fredrik Norling’s Standby Dialog Custom Control on XSnippets.
The final step is to set dojoParseOnLoad=”true” and add the dojo module dojo.behavior onto your XPage.
The result is then (Font) Awesome category icons on the Data View.