Greetings,
I have the following custom object called 'ProductInterest' in our CRM, this object includes a number of values, one of which is productName. A client can have multiple products (ProductName). If I drag and drop the field to the token script area, it shows as ${ProductInterestList.get(0).ProductName}
I am trying to write a Velocity Script Token to display an image based on what Products (ProductName) they are a member of. Token name is {{my.image}} and in the email I am calling it something like this
<img src="{{my.image}}" alt="">
The Velocity Script Token:
#if( $ProductInterest.ProductName == 'product1' || $ProductInterest.ProductName == 'product2' || $ProductInterest.ProductName == 'product3' )
http://www.myurl.com/images/Banner1.jpg
#else
http://www.myurl.com/images/Banner2jpg
#end
This is not working, the result is always Banner2 (the #else image) when testing on a lead that has either product 1, 2 or 3 only... any idea's?
(I even tried
#if( $ProductInterest.ProductName == 'product1' )
#elseif( $ProductInterest.ProductName == 'product2' )
#elseif( $ProductInterest.ProductName == 'product3' )
http://info.lazardnet.com/rs/211-JCD-267/images/Banner factsheet EMD_II.jpg
#else
http://info.lazardnet.com/rs/211-JCD-267/images/Banner factsheet.jpg
#end)
Solved! Go to Solution.
Ed, I'd use an extensible approach like so:
## Set up your map of products to related asset(s)
#set( $assetsByProduct = {
"product1|product2|product3" : {
"banner" : "BannerA.jpg"
},
"product4|product5" : {
"banner" : "BannerB.jpg"
},
"product6|product7|product8" : {
"banner" : "BannerC.jpg"
},
"" : {
"banner" : "DefaultBanner.gif"
}
} )
##
## Start w/default asset set (empty key)
#set( $assets = $assetsByProduct[""] )
##
## Guard against bad inputs (null or empty object list)
#if( $ProductInterestList && !$ProductInterestList.isEmpty() )
##
## Loop backwards through objects (standard foreach is fwd only)
#foreach( $idx in [$math.sub($ProductInterestList.size(),1)..0] )
#set( $interest = $ProductInterestList[$idx] )
#foreach( $assetSet in $assetsByProduct.keySet() )
##
## If we find a regex match for [map key,ProductName] we're done
#if( $interest.ProductName.matches("(?i)${assetSet}") )
#set( $assets = $assetsByProduct[$assetSet] )
#break($foreach.parent)
#end
#end
#end
#end
<img src="http://www.example.com/rs/${assets.banner}">
It's actually very simple logic, but Velocity is wordy (the same concept in JS would be half as long, for example there you have Array#reverse() while in VTL that doesn't exist as a built-in function).
The gist is:
It's extensible because you can add any other ProductInterest-specific data you want -- not just the "banner" property, but any other data that goes with the product. The $assetsByProduct map could be in its own script token for modularity.
Note the code uses a naive ordering to loop backward through the custom objects by index. You might want to sort them by some other property.
Final note: I added tabs for visual clarity. You'll want to delete them from your token (whitespace in Velocity doesn't disappear on its own, you may recall from other posts).
Hi Ed,
ProductInterest is a multi record array, since by design there is a 1-N relationsgip between leads and ProductInterest.
Hence the notation ${ProductInterestList.get(0).ProductName} that returns the first occurence of Producs interest for the lead.
#if( ${ProductInterestList.get(0).ProductName} == 'product1' || ${ProductInterestList.get(0).ProductName} == 'product2' || ${ProductInterestList.get(0).ProductName} == 'product3' )
http://www.myurl.com/images/Banner1.jpg
#else
http://www.myurl.com/images/Banner2jpg
#end
You could also store ${ProductInterestList.get(0).ProductName} in a variable and test this variable
#set($ProductInterest = ProductInterestList.get(0).ProductName)
#if( $ProductInterest == 'product1' || $ProductInterest == 'product2' || $ProductInterest == 'product3' )
http://www.myurl.com/images/Banner1.jpg
#else
http://www.myurl.com/images/Banner2jpg
#end
Also, please remember that if you have more than 1 product interest for a lead, only the ten most recently updated objects of a type are loaded. The list is ordered from most to least recently updated record.
-Greg
Hi Greg,
Thank you for the prompt reply, I have tried
#set($ProductInterest = $ProductInterestList.get(0).ProductName)
#if( $ProductInterest == 'product1' || $ProductInterest == 'product2' || $ProductInterest == 'product3' )
http://www.myurl.com/images/Banner1.jpg
#else
http://www.myurl.com/images/Banner2jpg
#end
Still only returning the second Banner. I have double checked the lead I am testing has Product 1 and should receive Banner1
Ok after double checking the Lead, it seems he had product 1, product 2, product 3 and product 4 so the logic I presume is taking the last product he has (product4) and returning the "#else" for banner 2. When I added product 4 to the If statement it returned the right Banner. So the question is how do I re-write the code to check if a lead has 'either product 1, 2 or 3' even if they have other products, to display banner 1?
Hi Ed,
You will have to iterate through the values (Attention, Velocity will only process the 10 most recent, even if a lead has more than 10), set a flag and test the flag after the loop.
Look here for some examples: http://developers.marketo.com/email-scripting/examples/
-Greg
Thanks again Greg..
Will do the research, atleast now I am on the right track, again appreciate the help...
I'll put up some code lat'ron. There's a pretty concise way to do this.
Ed, I'd use an extensible approach like so:
## Set up your map of products to related asset(s)
#set( $assetsByProduct = {
"product1|product2|product3" : {
"banner" : "BannerA.jpg"
},
"product4|product5" : {
"banner" : "BannerB.jpg"
},
"product6|product7|product8" : {
"banner" : "BannerC.jpg"
},
"" : {
"banner" : "DefaultBanner.gif"
}
} )
##
## Start w/default asset set (empty key)
#set( $assets = $assetsByProduct[""] )
##
## Guard against bad inputs (null or empty object list)
#if( $ProductInterestList && !$ProductInterestList.isEmpty() )
##
## Loop backwards through objects (standard foreach is fwd only)
#foreach( $idx in [$math.sub($ProductInterestList.size(),1)..0] )
#set( $interest = $ProductInterestList[$idx] )
#foreach( $assetSet in $assetsByProduct.keySet() )
##
## If we find a regex match for [map key,ProductName] we're done
#if( $interest.ProductName.matches("(?i)${assetSet}") )
#set( $assets = $assetsByProduct[$assetSet] )
#break($foreach.parent)
#end
#end
#end
#end
<img src="http://www.example.com/rs/${assets.banner}">
It's actually very simple logic, but Velocity is wordy (the same concept in JS would be half as long, for example there you have Array#reverse() while in VTL that doesn't exist as a built-in function).
The gist is:
It's extensible because you can add any other ProductInterest-specific data you want -- not just the "banner" property, but any other data that goes with the product. The $assetsByProduct map could be in its own script token for modularity.
Note the code uses a naive ordering to loop backward through the custom objects by index. You might want to sort them by some other property.
Final note: I added tabs for visual clarity. You'll want to delete them from your token (whitespace in Velocity doesn't disappear on its own, you may recall from other posts).
Again a perfect solution, Thank you again for a detailed and well explained reply... This can easily be your next blog post!