Say you have Badges Earned Custom Object ($BadgesEarned_cList in Velocity) to store a lead’s community achievements. Values are like so:
{description=Onboarding, points=200}
{description=Influencer, points=500}
{description=Helpful, points=200}
{description=Evangelist, points=350}
And you want to display the lead’s badges in a table with N alternating background colors. For example, with 3 alternating colors (leave aside the garish color scheme, that's not the point!):
This is is an old-school task that just about any template language can handle.[1] To start, we’ll stick with generic methods; later, we’ll see how Velocity’s Alternator helper class can save 1 or 2 lines of code.
As in other languages, alternation means a loop plus a modulo function (or native modulo operator[2]) which in Velocity is MathTool.mod:
#set( $rowColors = ["#ff4400", "#ccff00", "#0099cc"] )
#set( $numRowColors = $rowColors.size() )
#if( !$BadgesEarned_cList.isEmpty() )
<table style="border-top:10px solid #aaa;">
<tr bgcolor="#fff">
<td>Activity</td>
<td>Points Earned</td>
</tr>
#foreach( $badge in $BadgesEarned_cList )
#set( $rowColor = $rowColors[$math.mod($foreach.index, $numRowColors)] )
<tr bgcolor="${rowColor}" style="color:#333;">
<td>${badge.description}</td>
<td>${badge.points}</td>
</tr>
#end
</table>
#end
So I first set up an ArrayList, $rowColors, with the colors I want to alternate (in order from the top).
Then on every loop I get the modulo N of the loop index where N is the number of items in $rowColors. (The list happens to have 3 items now, but the code dynamically adjusts if you add/remove colors.)
The HTML output is like so:
<tablestyle="border-top: 10px solid #aaa;">
<tr bgcolor="#fff">
<td>Activity</td>
<td>Points Earned</td>
</tr>
<tr bgcolor="#ff4400"style="color:#333;">
<td>Onboarding</td>
<td>200</td>
</tr>
<tr bgcolor="#ccff00"style="color:#333;">
<td>Influencer</td>
<td>500</td>
</tr>
<tr bgcolor="#0099cc"style="color:#333;">
<td>Helpful</td>
<td>200</td>
</tr>
<tr bgcolor="#ff4400"style="color:#333;">
<td>Evangelist</td>
<td>350</td>
</tr>
</table>
You’ve seen above that without any “alternator-aware” code you can get exactly the output you want.
Velocity does offer a cool tool that abstracts away the modulo stuff. But as you can see in the Alternator source, it uses exactly the same method, just as compiled Java:
An Alternator might be infinitesimally faster because it’s compiled, but you’d never notice this in reality. The reason to use Alternators is to save lines of code, and every line does count in a language as verbose as VTL. Here’s how to get the same output using an Alternator:
#set( $rowColors = $alternator.manual(["#ff4400", "#ccff00", "#0099cc"]) )
#if( !$BadgesEarned_cList.isEmpty() )
<table style="border-top:10px solid #aaa;">
<tr bgcolor="#fff">
<td>Activity</td>
<td>Points Earned</td>
</tr>
#foreach( $badge in $BadgesEarned_cList )
#set( $rowColor = $rowColors.getNext() )
<tr bgcolor="${rowColor}" style="color:#333;">
<td>${badge.description}</td>
<td>${badge.points}</td>
</tr>
#end
</table>
#end
16 lines instead of 17: yay! And a little easier to read, maybe.
Create an Alternator object by passing a List to $alternator.manual. Velocity then handles the modulo-based loop internally, whenever you call getNext().
(If you’re confused about the difference between auto and manual, I don’t blame you, but trust me that manual + getNext() is what you always want, especially because of the more advanced application we’re going to do next.)
Alternating between Strings (single hex colors like “#ff4400”) is a simple task.
But let’s say you want to vary the background and foreground (text) colors for optimal contrast:
Now, you’ve got a set of 3 “color schemes” and each scheme has 2 characteristics (background and foreground). You should already be thinking: an array of objects!
And that’s exactly what I do here, passing an [] of {}s – an ArrayList of LinkedHashMaps, technically – to AlternatorTool:
#set( $rowColorSchemes = $alternator.manual([
{
"bg" : "#ff4400",
"fg" : "#fee"
},
{
"bg" : "#ccff00",
"fg" : "#333"
},
{
"bg" : "#0099cc",
"fg" : "#ccff00"
}
]) )
#if( !$BadgesEarned_cList.isEmpty() )
<table style="border-top:10px solid #aaa;">
<tr bgcolor="#fff">
<td>Activity</td>
<td>Points Earned</td>
</tr>
#foreach( $badge in $BadgesEarned_cList )
#set( $rowColorScheme = $rowColorSchemes.getNext() )
<tr bgcolor="${rowColorScheme.bg}" style="color:${rowColorScheme.fg};">
<td>${badge.description}</td>
<td>${badge.points}</td>
</tr>
#end
</table>
#end
Each HashMap has two keys, bg and fg. Notice I only call getNext() once per iteration to advance to the next object in the List.
The generated HTML:
<tablestyle="border-top:10px solid #aaa;">
<tr bgcolor="#fff">
<td>Activity</td>
<td>Points Earned</td>
</tr>
<tr bgcolor="#ff4400"style="color:#fee;">
<td>Onboarding</td>
<td>200</td>
</tr>
<tr bgcolor="#ccff00"style="color:#333;">
<td>Influencer</td>
<td>500</td>
</tr>
<tr bgcolor="#0099cc"style="color:#ccff00;">
<td>Helpful</td>
<td>200</td>
</tr>
<tr bgcolor="#ff4400"style="color:#fee;">
<td>Evangelist</td>
<td>350</td>
</tr>
</table>
That’s it for Alternators for today! But I have another post ready to go on how to combine Iterators and Alternators for some advanced fun. Stay tuned.
[1] Many template systems have macros for N = 2, like isOdd and isEven, built-in. Few offer anything as flexible as AlternatorTool.
[2] Indeed, Java operators like % are semi-supported in Velocity as well. But the VTL parser is much stricter than Java’s, leading to hard-to-debug problems. I always use the MathTool methods instead.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.