SOLVED

Email script - ${lead.Interest} contains "A"

Go to solution
Charles_THIERY
Level 3

Hello,

I don't manage to find on the documentation a way to use VTL in order to make a #if conditions for searching a specific value coming from a Marketo field.

Does anybody could help me on this please?

eg:

<ul>

#if(${lead.Interest}.contains("Performance"))

    <li>Performance</li>

#end

</ul>

BR,

Charles

1 ACCEPTED SOLUTION
SanfordWhiteman
Level 10 - Community Moderator

Should post to Products, not Champions (this space is to discuss the Champions program itself).

For a case-sensitive partial match you want

#if( $lead.Interest__c.contains("Performance") )

Note this will also match on "Power, LowPerformancer, Strength".

Matching that is less prone to error uses a regex:

#set( $item = "Performance" )

#if( $lead.Interest__c.matches("(?i)(.*)(^|,)\s*${item}\s*(,|$)(.*)") )

In general, "list-like" strings should be avoided unless you can make absolutely sure that the delimiter ("," in this case) cannot appear unescaped within an item. That is, if an item has a comma inside it -- which is totally possible with a string unless you control all the input -- parsing becomes problematic. Instead use a known structure like a JSON array.

(Geoff, you don't need curlies around a token if it isn't enclosed within quotes or output.)

ETA: Putting the matching item in a separate var will be more maintainable.

View solution in original post

14 REPLIES 14
Geoff_Krajeski1
Level 10 - Champion Alumni

You should likely be able to use ${{my.token}}.indexOf('A')

eg:

<ul>

#if(${lead.Interest}.indexOf("Performance"))

    <li>Performance</li>

#end

</ul>

Charles_THIERY
Level 3

Hi Geoff,

Thanks for the quick reply but I got this error:

An error occurred when procesing the email Body!

Lexical error, Encountered: "i" (105), after : "." at *unset*[line 90, column 25] near

<ul>
#if(${lead.Interest}.indexOf("Performance"))
    <li>Performance</li>
#end
</ul>

Maybe, I should clarify what I'm looking for:

My field ${lead.Interest} contains value like "A, B, C, D, ..." and I want to test on a specific value for creating a bullet point.

Any guess on why it's not working please?

Geoff_Krajeski1
Level 10 - Champion Alumni

woops.... need double curly braces around the token... my bad

Charles_THIERY
Level 3

Still not working...

An error occurred when procesing the email Body!

Encountered "{" near

<ul>
#if(${{lead.Interest__c}}.indexOf('Performance'))
    <li>Performance</li>
#end
SanfordWhiteman
Level 10 - Community Moderator

Should post to Products, not Champions (this space is to discuss the Champions program itself).

For a case-sensitive partial match you want

#if( $lead.Interest__c.contains("Performance") )

Note this will also match on "Power, LowPerformancer, Strength".

Matching that is less prone to error uses a regex:

#set( $item = "Performance" )

#if( $lead.Interest__c.matches("(?i)(.*)(^|,)\s*${item}\s*(,|$)(.*)") )

In general, "list-like" strings should be avoided unless you can make absolutely sure that the delimiter ("," in this case) cannot appear unescaped within an item. That is, if an item has a comma inside it -- which is totally possible with a string unless you control all the input -- parsing becomes problematic. Instead use a known structure like a JSON array.

(Geoff, you don't need curlies around a token if it isn't enclosed within quotes or output.)

ETA: Putting the matching item in a separate var will be more maintainable.

Charles_THIERY
Level 3

Hello Sandford,

Thank you for your answer. it works perfectly as long as I have the delimiter "," with or without space next to it.

I'm just wondering how it would have been possible for me to find your answer on my own. Do you have a documentation or website to recommend me please?

I'm really amazed by your add "(?i)(.*)(^|,)\s*" & "\s*(,|$)(.*)" which is definitely something that I can't understand.

BR,

Charles

SanfordWhiteman
Level 10 - Community Moderator

Hi Charles! Glad it's working.

I recommend my blog posts on Velocity (http://blog.teknkl.com/tag/velocity) or really my whole blog. I'm the only person regularly posting on this development stuff with a Marketo focus.

I try to write for the power user who wants to become a junior developer, as opposed to for full-blown techies, so the path to learning is somewhat easier.

Velocity is a simplified subset of Java, but that means it's simpler than... one of the most complex and mature modern programming languages! The programmer-y roots are always there. For example, the contains() and matches() methods above are Java String methods, which are best learned from Java docs/books/blogs, even though those reference materials are targeted at professional programmers as opposed to "email scripters."

The pattern in my matches() call is a regular expression, and a pretty simple/clunky one at that. It means "zero or more characters, followed by either the start of a string or a comma, followed by zero or more spaces, followed by the word 'Performance', followed by zero or more spaces, followed by either the end of the string or a comma, followed by zero or more characters." So describing the ways in which your list-like string can contain "Performance" and accounting for human error (extra spaces) and any order or number of items. Oh, and case-insensitive (?i).

Charles_THIERY
Level 3

Hi Sandford,

What is the way to make the negative test of what I have previously asked and with ";" instead of "," please? I thought by Adding "!" at the beginning would work... but it seems to not working:

  1. #set( $item = "Performance" )
  2. #set( $item2 = "Talent" )
  3. #if( !$lead.Interest__c.matches("(?i)(.*)(^|;)\s*${item}\s*(;|$)(.*)") ) 
  4. #elseif( !$lead.Interest__c.matches("(?i)(.*)(^|;)\s*${item2}\s*(;|$)(.*)") ) 
  5. #else

Sorry, you become a kind of my guru!

BR,

Charles

SanfordWhiteman
Level 10 - Community Moderator

When you reach the point of two lookups as opposed to a one-off, you don't want to repeat the same code. This is known the as the DRY principle in programming. As you will see below, the moment you add a second check, you want to refactor the whole approach because otherwise you will eventually screw up due to mistyping, and people will have trouble reading your code.

(There's nothing about two mostly-identical strings that says, "These are always supposed to differ only by this one character": they might as well differ by 100 characters. Totally identical strings in different lines of code also can't inform the reader -- which doesn't have to be someone else, it could be you a year from now  -- "Whatever string you put in Line 2 must be repeated in Line 4.")

Another incredibly useful way to frame your thinking is the Zero-One-Infinity principle.  For our purposes here, ZOI means that once you decide you want two lookups, you have to assume there will be a much higher number of lookups (maybe not "infinity" as the principle suggests, but the idea is "more than 1 = much more than 1"). ZOI means you should treat 2 as if it were 20, 200, or 2000. Imagine how crazy your script token would get if you copy-and-pasted-and-slightly-altered your code just 20 times.  Obey the DRY principle accordingly.

## generic list-like string scanner w/selectable delimiter

#macro( listContains $haystack $needle $delim )

#if( $haystack.matches("(?i)(.*)(${delim}|^)\s*${needle}\s*(${delim}|$)(.*)") )

true##

#else

false##

#end

#end

## convenience call w/semicolon

#macro( semiListContains $haystack $needle )

#listContains( $haystack $needle ';' )

#end

## convenience call w/comma

#macro( commaListContains $haystack $needle )

#listContains( $haystack $needle ',' )

#end

#if( "#semiListContains( $lead.Interest__c 'Talent' )" == "true" )

Does contain Talent.

#end

#if( !("#semiListContains( $lead.Interest__c 'Performance' )" == "true") )

Doesn't contain Performance.

#end

Charles_THIERY
Level 3

Hello Sanford,

I got your point and therefore I want to reduce my code as the minimum length possible and try to concentrate the editable section of my code on the top of my script.

I've seen your post on http://blog.teknkl.com/marketo-doesnt-like-velocimacros-for-output-but-define-is-fine/  but not sure if it's working out of a macro.

Anyway, I wanted to know if there is an expression in order to do this:

#set( $TP = "TP_A", "TP_B")

#set( $TP_A = "Button A", "https://www.wonderfulworld.com")

#set( $TP_B = "Button B", "https://www.hellworld.com")

#foreach( $asset in $TP )

     #if($lead.notengagedAssets.matches("(?i)(.*)(^|;)\s*${asset}\s*(;|$)(.*)") )

          <a href="${${asset}[1]}">${${asset}[0]}</a>

          ##I want to get the label out of the ${asset} variable and add the [...] to indicate which parameters to retreive.

     #end

#end

##The result expected should be:

          <a href="https://www.wonderfulworld.com">Button A</a>

          <a href="https://www.hellworld.com">Button B</a>

Is it possible? would it mess with the email click tracking of Marketo?

BR,

Charles

SanfordWhiteman
Level 10 - Community Moderator

Please open a new thread in Products (this shouldn't be in Champions, which is for Qs about the Champs program).

Charles_THIERY
Level 3

Hello Sanford,

Thank for this answer. I really need to dig into your proposal as it turns I have to create more complex dynamic email structure.

BR,

Charles

Geoff_Krajeski1
Level 10 - Champion Alumni

So, it is best to use the SFDC/API name, Sandy? i.e.. Interest__c?

SanfordWhiteman
Level 10 - Community Moderator

Well, I'd say use the VTL name, since you have to select the prop from the tree of fields anyway.