Take this VTL snippet, intended to output trial keys for known combos of Country and custom field Intended Use:
#if( $lead.Intended_Use__c.equals("MycoAlert Trial Kit")) && ($lead.Country.equals("United States") )
KGFV-WJN7-CW43
#elseif( $lead.Intended_Use__c.equals("MycoAlert Plus Trial Kit")) && ($lead.Country.equals("United States") )
7XFC-WFZP-CTDY
#elseif( $lead.Intended_Use__c.equals("MycoAlert Trial Kit")) && ($lead.Country.equals("Austria") )
VTQF-RL0D-Q6NJ
#elseif( $lead.Intended_Use__c.equals("MycoAlert Plus Trial Kit")) && ($lead.Country.equals("Austria") )
QZIC-L36N-2BDQ
#end
At a glance, what do you think the output will be for this lead:
Now click below to reveal the actual output:
Not what you expected?
Perhaps you counted the right and left parentheses, and indeed there are four opening (
and four closing )
on each line. But you missed that:
&&
“operator” isn’t an operator here: it’s outside of the #elseif()
directive, so it’s just just two ampersand characters with no special meaning$lead.Country.equals("United States")
is also outside the #elseif()
, so it’s treated as standalone output
See, Velocity — like all template languages — centers on output. So anything between #
-directives or $
-references, as long as it doesn’t otherwise violate VTL grammar, is assumed to be a literal string.
You couldn’t get away with that wandering &&
in non-template languages. In JS, for example, this is a fatal syntax error:
if( lead.someProperty === "Some Value" ) { &&
}
Here’s the code you probably thought you were seeing above:
#if( $lead.Intended_Use__c.equals("MycoAlert Trial Kit") && $lead.Country.equals("United States") )
KGFV-WJN7-CW43
#elseif( $lead.Intended_Use__c.equals("MycoAlert Plus Trial Kit") && $lead.Country.equals("United States") )
7XFC-WFZP-CTDY
#elseif( $lead.Intended_Use__c.equals("MycoAlert Trial Kit") && $lead.Country.equals("Austria") )
VTQF-RL0D-Q6NJ
#elseif( $lead.Intended_Use__c.equals("MycoAlert Plus Trial Kit") && $lead.Country.equals("Austria") )
QZIC-L36N-2BDQ
#end
Now, the &&
is an actual operator and $lead.Country
is part of the condition.
The fixed code above will work, but it’s hard to maintain as string constants are peppered throughout the code.
Better to use a map-first approach where you put all the strings up top, leaving you with only one line of “code” proper!
#set( $trialKeyPatterns = {
["MycoAlert Trial Kit","United States"] : "KGFV-WJN7-CW43",
["MycoAlert Plus Trial Kit","United States"] : "7XFC-WFZP-CTDY",
["MycoAlert Trial Kit","Austria"] : "VTQF-RL0D-Q6NJ",
["MycoAlert Plus Trial Kit","Austria"] : "QZIC-L36N-2BDQ"
})
${trialKeyPatterns.get([$lead.Intended_Use__c, $lead.Country])}
This works because the keys of a Java LinkedHashMap use value equivalence (equals
), rather than reference equality (==
).✱ So map.get(key)
finds the item whose key equals(key)
. Here, key
is an ArrayList, and ArrayList.equals means “Are all indexes and items equal?”
In other words:
#set( $listA = ["MycoAlert Trial Kit","United States"] )
#set( $listB = ["MycoAlert Trial Kit","United States"] )
#set( $areTheyEqual = $listA.equals($listB) ) ## true
#set( $listC = ["United States","MycoAlert Trial Kit"] )
#set( $areTheyEqual = $listA.equals($listC) ) ## false
#set( $mapD = {
$listA : "hello"
} )
#set( $getKey = $mapD.get($listA) ) ## "hello"
#set( $getKey = $mapD.get($listB) ) ## "hello"
#set( $getKey = $mapD.get($listC) ) ## null
✱ Yes, the terms are kind of confusing, even more so when you consider that Velocity ==
, which we’re constantly reminding people not to use because it can act weird, isn’t the same as Java ==
.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.